this.DataBindings.Add(new Binding("Text", brain, "Dump"));

Development and .Net

  Home  |   Contact  |   Syndication    |   Login
  5 Posts | 0 Stories | 3 Comments | 3 Trackbacks

News

Archives

Post Categories

.Net Development

I've been reading about one of the obscure new features of .Net 2.0 called DynamicMethods.  Part of the System.Reflection.Emit namespace, the DynamicMethod class allows you to create and execute methods at runtime without creating any dynamic assembly or dynamic type.

This by itself sounds interesting, but not very useful.  I mean how often do you have the need to dynamic generate methods?  Except for certain situations, not very often if at all.  But DynamicMethods have one other interesting feature. If the DynamicMethod is bound to a particular Type, then the generated method has access to the private members of that type.

Here's a small example (important code only):

public partial class Form1 : Form
    {
        
DynamicMethod _dMethod;

        
public Form1()
        {
            InitializeComponent();
            _dMethod = CreateDynamicMethod();
        }

        
private DynamicMethod CreateDynamicMethod()
        {
            
DynamicMethod dmethod = new DynamicMethod("", typeof(int), new Type[] { typeof(TextBoxBase) }, typeof(TextBoxBase));
            
ILGenerator igen = dmethod.GetILGenerator();

            
FieldInfo field = typeof(TextBoxBase).GetField("maxLength", BindingFlags.NonPublic | BindingFlags.Instance);

            igen.Emit(
OpCodes.Ldarg_0);
            igen.Emit(
OpCodes.Ldfld, field);
            igen.Emit(
OpCodes.Ret);

            
return dmethod;
        }

        
private void button1_Click(object sender, EventArgs e)
        {
            
Random r = new Random();
            textBox1.MaxLength = r.Next(1, 4096);

            label1.Text =
"Max Length = " + textBox1.MaxLength.ToString();
        }

        
private void button2_Click(object sender, EventArgs e)
        {
            
MessageBox.Show("Max Length = " + ((int)_dMethod.Invoke(textBox1, new object[] { textBox1 })).ToString());
        }
    }

This is a simple Windows Application that contains one TextBox, one Label, and two Buttons.  The first button (button2) sets the MaxLength property of the TextBox to a random number between 1 and 4096 and sets the Label's Text property to that value.  Then second button executes the generated function that was generated at the form's creation and shows the returned value in a MessageBox.  Now note what the generated function is doing, specifically this line:

    FieldInfo
field = typeof(TextBoxBase).GetField("maxLength", BindingFlags.NonPublic | BindingFlags.Instance);

The function is using a private instance field called maxLength, which belongs to the abstract class TextBoxBase (I used Lutz'a Reflector to find out what the name of the field was).  The function then just returns the value of the field.  So the generated function was able to access the pri
vate instance field for the abstract parent of the TextBox object.

There are two drawbacks with these DynamicMethods when compared to the Extension Methods of C# 3.0.

1)  You must have a reference to the created DynamicMethod object or the delegate created by the DynamicMethod's CreateDelegate function.
2)  You have to use IL OpCodes to generate the body of your runtime function.

Now I have to think up some practical examples (not counting dynamic delegates for events).

Some interesting links:
    DebuggerVisualizer for DynamicMethod (Show me the IL)
    To generate an event handler at run time by using a dynamic method
    Fast late-bound invocation through DynamicMethod delegates

Here's the full code from the example above:

using
System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Windows.Forms;

namespace DynamicMethodTest
{
    
public partial class Form1 : Form
    {
        
DynamicMethod _dMethod;

        
public Form1()
        {
            InitializeComponent();
            _dMethod = CreateDynamicMethod();
        }

        
private DynamicMethod CreateDynamicMethod()
        {
            
DynamicMethod dmethod = new DynamicMethod("Hello", typeof(int), new Type[] { typeof(TextBoxBase) }, typeof(TextBoxBase));
            
ILGenerator igen = dmethod.GetILGenerator();

            
FieldInfo field = typeof(TextBoxBase).GetField("maxLength", BindingFlags.NonPublic | BindingFlags.Instance);

            igen.Emit(
OpCodes.Ldarg_0);
            igen.Emit(
OpCodes.Ldfld, field);
            igen.Emit(
OpCodes.Ret);

            
return dmethod;
        }

        
private void button1_Click(object sender, EventArgs e)
        {
            
Random r = new Random();
            textBox1.MaxLength = r.Next(1, 4096);

            label1.Text =
"Max Length = " + textBox1.MaxLength.ToString();
        }

        
private void button2_Click(object sender, EventArgs e)
        {
            
MessageBox.Show("Max Length = " + ((int)_dMethod.Invoke(textBox1, new object[] { textBox1 })).ToString());
        }

        
/// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        
/// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            
if (disposing && (components != null))
            {
                components.Dispose();
            }
            
base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        
/// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            
this.textBox1 = new System.Windows.Forms.TextBox();
            
this.button1 = new System.Windows.Forms.Button();
            
this.button2 = new System.Windows.Forms.Button();
            
this.label1 = new System.Windows.Forms.Label();
            
this.SuspendLayout();
            
//
            // textBox1
            //
            this.textBox1.Location = new System.Drawing.Point(13, 13);
            
this.textBox1.Name = "textBox1";
            
this.textBox1.Size = new System.Drawing.Size(100, 20);
            
this.textBox1.TabIndex = 0;
            
//
            // button2
            //
            this.button2.Location = new System.Drawing.Point(205, 9);
            
this.button2.Name = "button1";
            
this.button2.Size = new System.Drawing.Size(75, 23);
            
this.button2.TabIndex = 1;
            
this.button2.Text = "Execute";
            
this.button2.UseVisualStyleBackColor = true;
            
this.button2.Click += new System.EventHandler(this.button2_Click);
            
//
            // button1
            //
            this.button1.Location = new System.Drawing.Point(205, 39);
            
this.button1.Name = "button2";
            
this.button1.Size = new System.Drawing.Size(75, 23);
            
this.button1.TabIndex = 2;
            
this.button1.Text = "Set Length";
            
this.button1.UseVisualStyleBackColor = true;
            
this.button1.Click += new System.EventHandler(this.button1_Click);
            
//
            // label1
            //
            this.label1.AutoSize = true;
            
this.label1.Location = new System.Drawing.Point(13, 48);
            
this.label1.Name = "label1";
            
this.label1.Size = new System.Drawing.Size(75, 13);
            
this.label1.TabIndex = 3;
            
this.label1.Text = "Max Length = ";
            
//
            // Form1
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            
this.ClientSize = new System.Drawing.Size(292, 273);
            
this.Controls.Add(this.label1);
            
this.Controls.Add(this.button2);
            
this.Controls.Add(this.button1);
            
this.Controls.Add(this.textBox1);
            
this.Name = "Form1";
            
this.Text = "Form1";
            
this.ResumeLayout(false);
            
this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.TextBox textBox1;
        
private System.Windows.Forms.Button button1;
        
private System.Windows.Forms.Button button2;
        
private System.Windows.Forms.Label label1;
    }
}
  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
posted on Monday, January 30, 2006 10:44 AM

Feedback

# re: DynamicMethod - New .Net 2.0 Feature 6/21/2006 9:57 AM Sugar Coded
A brilliant example, well done

# re: DynamicMethod - New .Net 2.0 Feature 12/16/2007 2:02 PM Julien Couvreur
If you're interested, I have an example of dynamically generated event handler, for unittesting async methods:
http://code.google.com/p/jcouv/wiki/CallbackWaiter

The CallbackWaiter can generate mock event handlers which records all the events into a queue for later checking.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: