Export (0) Print
Expand All
This topic has not yet been rated - Rate this topic

How to: Define and Execute Dynamic Methods

The following procedures show how to define and execute a simple dynamic method and a dynamic method that is bound to an instance of a class. For more information about dynamic methods, see the DynamicMethod class and Reflection Emit Dynamic Method Scenarios.

To define and execute a simple dynamic method

  1. Declare a delegate type to execute the method. The following code declares the Square delegate type. The full example also uses the Func<T, TResult> generic delegate type to execute the SquareIt method.

    
    private delegate long Square(int input);
    
    
    
  2. Create an array that specifies the parameter types for the dynamic method. In this example, the only parameter is an int (Integer in Visual Basic), so the array has only one element.

    
    Type[] methodArgs = { typeof(int) };
    
    
    
  3. Create a DynamicMethod. In this example, the method is named SquareIt.

    Note Note:

    It is not necessary to give dynamic methods names, and they cannot be invoked by name. Multiple dynamic methods can have the same name. However, the name appears in call stacks and can be useful for debugging.

    The type of the return value is specified as long.

    
    DynamicMethod squareIt = new DynamicMethod(
        "SquareIt", 
        typeof(long), 
        methodArgs
    );
    
    
    
  4. Emit the method body. In this example, an ILGenerator object is used to emit the Microsoft intermediate language (MSIL).

    The MSIL in this example loads the argument, which is an int, onto the stack, converts it to a long, duplicates the long, and multiplies the two numbers. This leaves the squared result on the stack, and all the method has to do is return.

    
    ILGenerator il = squareIt.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Conv_I8);
    il.Emit(OpCodes.Dup);
    il.Emit(OpCodes.Mul);
    il.Emit(OpCodes.Ret);
    
    
    
  5. Create an instance of the delegate (declared in step 1) that represents the dynamic method by calling the CreateDelegate method. Creating the delegate completes the method, and any further attempts to change the method — for example, by adding more MSIL — are ignored. The following code creates a delegate of type Square and invokes it, formatting the result and appending it to the output text block. The code then creates a generic delegate of type Func<T, TResult> and invokes it.

    Note Note:

    The CreateDelegate method returns the Delegate type, so the return value must be cast to the correct type.

    
    Square invokeSquareIt = 
        (Square) squareIt.CreateDelegate(typeof(Square));
    
    outputBlock.Text += String.Format("123456789 squared = {0}\n",
        invokeSquareIt(123456789));
    
    Func<int, long> invokeGeneric = 
        (Func<int, long>) squareIt.CreateDelegate(typeof(Func<int, long>));
    
    outputBlock.Text += String.Format("987654321 squared = {0}\n",
        invokeGeneric(987654321));
    
    
    

To define and execute a dynamic method that is bound to an object

  1. Declare a delegate type to execute the method. The following code declares two delegate types: The Bound type is used to bind the method to an instance of Example, and the Unbound type is used to execute the method with an instance of Example that is passed as a parameter of the delegate.

    Note Note:

    As with the previous procedure, generic delegates could be used to avoid declaring delegate types (in both bound and unbound cases). Ordinary delegates are used here to simplify the code.

    
    private delegate int Bound(int input);
    private delegate int Unbound(Example target, int input);
    
    
    
  2. Create an array that specifies the parameter types for the dynamic method. If the delegate that represents the method is to be bound to an object, the first parameter must match the type the delegate is bound to. In this example, there are two parameters, of type Example and type int (Integer in Visual Basic).

    
    Type[] methodArgs2 = { typeof(Example), typeof(int) };
    
    
    
  3. Create a DynamicMethod. In this example, the method has no name. The type of the return value is specified as int (Integer in Visual Basic). In Silverlight, the method has access only to the public members of the Example class.

    
    DynamicMethod multiplyTestField = new DynamicMethod(
        "", 
        typeof(int), 
        methodArgs2
    );
    
    
    
  4. Emit the method body. In this example, an ILGenerator object is used to emit the MSIL.

    The MSIL in this example loads the first argument, which is an instance of the Example class, and uses it to load the value of Test, which is a public instance field of type int. The second argument is loaded, and the two numbers are multiplied. If the result is larger than int, the value is truncated and the most significant bits are discarded. The method returns with the return value on the stack.

    
    ILGenerator ilMP = multiplyTestField.GetILGenerator();
    ilMP.Emit(OpCodes.Ldarg_0);
    
    FieldInfo testInfo = typeof(Example).GetField("Test", 
        BindingFlags.Public | BindingFlags.Instance);
    
    ilMP.Emit(OpCodes.Ldfld, testInfo);
    ilMP.Emit(OpCodes.Ldarg_1);
    ilMP.Emit(OpCodes.Mul);
    ilMP.Emit(OpCodes.Ret);
    
    
    
  5. Create an instance of the Bound delegate (declared in step 1) that represents the dynamic method by calling the CreateDelegate(Type, Object) method overload. Creating the delegate completes the method, and any further attempts to change the method — for example, by adding more MSIL — are ignored.

    Note Note:

    You can call the CreateDelegate method multiple times to create delegates that are bound to other instances of the target type.

    The following code binds the method to a new instance of the Example class whose private test field is set to 42. That is, each time the delegate is invoked, the same instance of Example is passed to the first parameter of the method. When the delegate is invoked, only the second parameter is required. The delegate is invoked twice with different values.

    The program does not retain a reference to the new Example object, but the object can be accessed by using the Target property of the delegate. The code uses this fact to display the value of the Test field in the formatted output, and to change the value of the field before the delegate is invoked for the last time.

    
    Bound invoke = (Bound) multiplyTestField.CreateDelegate(
        typeof(Bound), new Example(42));
    
    outputBlock.Text += String.Format(
        "Example.Test = {0}; {1} * Example.Test = {2}\n", 
        ((Example)invoke.Target).Test, 3, invoke(3));
    outputBlock.Text += String.Format(
        "Example.Test = {0}; {1} * Example.Test = {2}\n", 
        ((Example)invoke.Target).Test, 5, invoke(5));
    
    ((Example)invoke.Target).Test *= 2;
    
    outputBlock.Text += String.Format(
        "Example.Test = {0}; {1} * Example.Test = {2}\n\n", 
        ((Example)invoke.Target).Test, 5, invoke(5));
    
    
    
  6. You can call the CreateDelegate method multiple times to create delegates that are bound to other instances of the target type. The following code creates a variable that contains an instance of Example, binds a new delegate to the instance, and invokes the delegate twice.

    Between invocations, the code uses the reference in the variable ex to change the value of the Test field.

    
    Example ex = new Example(5280);
    
    Bound another = 
        (Bound) multiplyTestField.CreateDelegate(typeof(Bound), ex);
    
    outputBlock.Text += String.Format(
        "Example.Test = {0}; {1} * Example.Test = {2}\n", 
        ex.Test, 3, another(3));
    
    ex.Test += 1;
    
    outputBlock.Text += String.Format(
        "Example.Test = {0}; {1} * Example.Test = {2}\n\n", 
        ex.Test, 3, another(3));
    
    
    
  7. You can call the method without binding it to an instance of Example. The following code creates a delegate of type Unbound, which has a parameter of type Example and a parameter of type int (Integer in Visual Basic). The code invokes the delegate twice, with two different instances of the Example class.

    
    Unbound notBound = 
        (Unbound) multiplyTestField.CreateDelegate(typeof(Unbound));
    
    outputBlock.Text += String.Format("{0} * Example.Test = {1}\n",
        10, notBound(new Example(42), 10));
    outputBlock.Text += String.Format("{0} * Example.Test = {1}\n",
        10, notBound(new Example(56), 10));
    
    
    

The following example demonstrates a simple dynamic method and a dynamic method that is bound to an instance of a class.

The simple dynamic method takes one argument, a 32-bit integer, and returns the 64-bit square of that integer. A generic delegate is used to invoke the method.

The second dynamic method has two parameters, of type Example and type int (Integer in Visual Basic). When the dynamic method has been created, it is bound to an instance of Example, using a delegate that has one argument of type int. The delegate does not have an argument of type Example, because the first parameter of the method always receives the bound instance of Example. When the delegate is invoked, only the int argument is supplied. This dynamic method accesses a public field of the Example class and returns the product of the public field and the int argument. The code example declares a delegate that matches the signature of the second method, and uses it to execute the method without binding it to an instance of Example.

The example defines delegates that can be used to execute the methods, and also executes the first method by using a generic delegate type that is provided by the .NET Framework class library.


using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

public class Example
{
    // The following constructor and public field are used to
    // demonstrate a method bound to an object.
    //
    public int Test;
    public Example(int test)
    {
        this.Test = test;
    }

    // The following delegates are used to invoke the methods.
    //
    private delegate long Square(int input);
    private delegate int Bound(int input);
    private delegate int Unbound(Example target, int input);

    public static void Demo(System.Windows.Controls.TextBlock outputBlock)
    {
        outputBlock.Text += "Example 1:\n\n";

        // Example 1: A simple dynamic method.
        //
        // Create an array that specifies the parameter types for the
        // dynamic method. In this example the only parameter is an 
        // Integer, so the array has only one element.
        //
        Type[] methodArgs = { typeof(int) };

        // Create a DynamicMethod. In this example the method is
        // named SquareIt. It is not necessary to give dynamic 
        // methods names. They cannot be invoked by name, and two
        // dynamic methods can have the same name. However, the 
        // name appears in calls stacks and can be useful for
        // debugging. 
        //
        // In this example the return type of the dynamic method
        // is Long. 
        //
        DynamicMethod squareIt = new DynamicMethod(
            "SquareIt", 
            typeof(long), 
            methodArgs
        );

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. DynamicMethod has an associated type
        // DynamicILInfo that can be used in conjunction with 
        // unmanaged code generators.
        //
        // The MSIL loads the argument, which is an Integer, onto the 
        // stack, converts the Integer to a Long, duplicates the top
        // item on the stack, and multiplies the top two items on the
        // stack. This leaves the squared number on the stack, and 
        // all the method has to do is return.
        //
        ILGenerator il = squareIt.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Conv_I8);
        il.Emit(OpCodes.Dup);
        il.Emit(OpCodes.Mul);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method. 
        // Creating the delegate completes the method, and any further 
        // attempts to change the method (for example, by adding more
        // MSIL) are ignored. 
        //
        // The following code shows how to use the Square delegate,
        // defined in this code example, and also Func, a generic 
        // delegate that can produce delegate types matching any
        // single-parameter method that has a return type.
        //
        Square invokeSquareIt = 
            (Square) squareIt.CreateDelegate(typeof(Square));

        outputBlock.Text += String.Format("123456789 squared = {0}\n",
            invokeSquareIt(123456789));

        Func<int, long> invokeGeneric = 
            (Func<int, long>) squareIt.CreateDelegate(typeof(Func<int, long>));

        outputBlock.Text += String.Format("987654321 squared = {0}\n",
            invokeGeneric(987654321));


        outputBlock.Text += "\nExample 2:\n\n";

        // Example 2: A dynamic method bound to an instance.
        //
        // Create an array that specifies the parameter types for a
        // dynamic method. If the delegate representing the method
        // is to be bound to an object, the first parameter must 
        // match the type the delegate is bound to. In the following
        // code the bound instance is an object of type Example. 
        //
        Type[] methodArgs2 = { typeof(Example), typeof(int) };

        // Create a DynamicMethod. In this example the method has no
        // name. The return type of the method is Integer. The method 
        // has access to the public members of the Example class. 
        //
        DynamicMethod multiplyTestField = new DynamicMethod(
            "", 
            typeof(int), 
            methodArgs2
        );

        // Emit the method body. In this example ILGenerator is used
        // to emit the MSIL. 
        //
        // The MSIL loads the first argument, which is an instance of
        // the Example class, and uses it to get the value of the public
        // instance field Text, of type Integer. The second argument 
        // is loaded, and the two numbers are multiplied. If the result
        // is larger than Integer, the value is truncated and the most 
        // significant bits are discarded. The method returns, with
        // the return value on the stack.
        //
        ILGenerator ilMP = multiplyTestField.GetILGenerator();
        ilMP.Emit(OpCodes.Ldarg_0);

        FieldInfo testInfo = typeof(Example).GetField("Test", 
            BindingFlags.Public | BindingFlags.Instance);

        ilMP.Emit(OpCodes.Ldfld, testInfo);
        ilMP.Emit(OpCodes.Ldarg_1);
        ilMP.Emit(OpCodes.Mul);
        ilMP.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method. 
        // Creating the delegate completes the method, and any further 
        // attempts to change the method  for example, by adding more
        // MSIL  are ignored. 
        // 
        // The following code binds the method to a new instance
        // of the Example class whose Test field is set to 42. That 
        // is, each time the delegate is invoked the same instance of
        // Example is passed to the first parameter of the method.
        //
        // The delegate Func is used, with a parameter of type Integer
        // and a return type of Integer. The delegate doesn't have a
        // parameter of type Example, because the instance of Example 
        // is bound to the delegate, and therefore acts like a hidden 
        // first parameter of the method.
        // 
        // The delegate is invoked invoked twice, with different 
        // argument values. 
        //
        // The program doesn't have a reference to the bound instance
        // of Example, but it can be accessed through the Target 
        // property of the delegate. The Target property is used to 
        // multiply the Test field by two, and the delegate is 
        // invoked again.
        //
        Bound invoke = (Bound) multiplyTestField.CreateDelegate(
            typeof(Bound), new Example(42));

        outputBlock.Text += String.Format(
            "Example.Test = {0}; {1} * Example.Test = {2}\n", 
            ((Example)invoke.Target).Test, 3, invoke(3));
        outputBlock.Text += String.Format(
            "Example.Test = {0}; {1} * Example.Test = {2}\n", 
            ((Example)invoke.Target).Test, 5, invoke(5));

        ((Example)invoke.Target).Test *= 2;

        outputBlock.Text += String.Format(
            "Example.Test = {0}; {1} * Example.Test = {2}\n\n", 
            ((Example)invoke.Target).Test, 5, invoke(5));

        // A second instance of Example is created, and bound to a new
        // instance of the delegate. The delegate is invoked twice, and 
        // between the two invocations the value of Test is incremented.
        //
        Example ex = new Example(5280);

        Bound another = 
            (Bound) multiplyTestField.CreateDelegate(typeof(Bound), ex);

        outputBlock.Text += String.Format(
            "Example.Test = {0}; {1} * Example.Test = {2}\n", 
            ex.Test, 3, another(3));

        ex.Test += 1;

        outputBlock.Text += String.Format(
            "Example.Test = {0}; {1} * Example.Test = {2}\n\n", 
            ex.Test, 3, another(3));

        // Finally, the example creates a delegate of type Unbound, which
        // takes two parameters: an instance of Example and an Integer.
        // This delegate calls the same method without binding it to an
        // instance of Example. The delegate is invoked with two new 
        // instances of Example.
        //
        Unbound notBound = 
            (Unbound) multiplyTestField.CreateDelegate(typeof(Unbound));

        outputBlock.Text += String.Format("{0} * Example.Test = {1}\n",
            10, notBound(new Example(42), 10));
        outputBlock.Text += String.Format("{0} * Example.Test = {1}\n",
            10, notBound(new Example(56), 10));
    }
}

/* This code example produces the following output:

Example 1:

123456789 squared = 15241578750190521
987654321 squared = 975461057789971041

Example 2:

Example.Test = 42; 3 * Example.Test = 126
Example.Test = 42; 5 * Example.Test = 210
Example.Test = 84; 5 * Example.Test = 420

Example.Test = 5280; 3 * Example.Test = 15840
Example.Test = 5281; 3 * Example.Test = 15843

10 * Example.Test = 420
10 * Example.Test = 560
 */


Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.