欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

定义和执行动态方法DynamicMethod DynamicMethod

程序员文章站 2022-05-28 07:49:56
...
using System;
using System.Reflection;
using System.Reflection.Emit;

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

    //1、声明用于执行方法的委托类型。 考虑使用泛型委托,将需要声明的委托类型数降到最低。 
    //以下代码声明两种可用于 SquareIt 方法的委托类型,其中一个是泛型。
    private delegate long SquareItInvoker(int input);

    private delegate TReturn OneParameter<TReturn, TParameter0>
        (TParameter0 p0);

    public static void Main()
    {
        // Example 1: 一个简单的动态方法
        //
        // 2、创建用于为动态方法指定参数类型的数组。 在此示例中,唯一的参数为 int(在 Visual Basic 中为 Integer),所以数组只有一个元素。
        //
        Type[] methodArgs = { typeof(int) };

        //3、 创建 DynamicMethod。 在此示例中,该方法命名为 SquareIt。
        //备注
       //不需要为动态方法命名,并且不能通过名称调用它们。 多个动态方法可以具有相同的名称。 但是,名称将在调用堆栈中显示并且可用于调试。
       //返回值的类型指定为 long。 该方法与包含 Example 类的模块关联,该类包含代码示例。 可以指定任何加载的模块。 动态方法的行为类似于模块级的 static 方法
        //
        DynamicMethod squareIt = new DynamicMethod(
            "SquareIt",
            typeof(long),
            methodArgs,
            typeof(Example).Module);

        // 4、发出方法主体。 在此示例中,使用 ILGenerator 对象发出 Microsoft 中间语言 (MSIL)。 
        //也可以结合使用 DynamicILInfo 对象与非托管代码生成器,发出 DynamicMethod 的方法主体。
        //此示例中的 MSIL 将该参数(一个 int)加载到堆栈上,将其转换为 long,复制 long,
        //然后将这两个数字相乘。 这会将平方结果保留在堆栈中,方法只需返回即可。
        //
        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、通过调用 CreateDelegate 方法创建表示动态方法的委托(在步骤 1 中声明)的实例。 
        //创建委托即完成该方法,任何更改方法的进一步尝试(例如,添加更多 MSIL)都将被忽略。 
        //以下代码使用泛型委托创建委托并调用它。
        //
        OneParameter<long, int> invokeSquareIt =
            (OneParameter<long, int>)
            squareIt.CreateDelegate(typeof(OneParameter<long, int>));

        Console.WriteLine("123456789 squared = {0}",
            invokeSquareIt(123456789));

        // Example 2: 绑定到实例的动态方法.
        //
        // 1、创建用于为动态方法指定参数类型的数组。 
        //如果表示方法的委托要绑定到对象,
        //则第一个参数必须与委托绑定到的类型相匹配。 
        //在此示例中,存在两个参数,分别属于 Example 和 int
        //
        Type[] methodArgs2 = { typeof(Example), typeof(int) };

        // Create a DynamicMethod. In this example the method has no
        // name. The return type of the method is int. The method 
        // has access to the protected and private data of the 
        // Example class.
        //
        DynamicMethod multiplyHidden = new DynamicMethod(
            "",
            typeof(int),
            methodArgs2,
            typeof(Example));

        // 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 first argument, which is an instance of
        // the Example class, and uses it to load the value of a 
        // private 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 ilMH = multiplyHidden.GetILGenerator();
        ilMH.Emit(OpCodes.Ldarg_0);

        FieldInfo testInfo = typeof(Example).GetField("test",
            BindingFlags.NonPublic | BindingFlags.Instance);

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

        //通过调用 CreateDelegate(Type, Object) 方法重载创建表示动态方法的委托(在步骤 1 中声明)的实例
        //
        OneParameter<int, int> invoke = (OneParameter<int, int>)
            multiplyHidden.CreateDelegate(
                typeof(OneParameter<int, int>),
                new Example(42)
            );

        Console.WriteLine("3 * test = {0}", invoke(3));
    }
}
/* This code example produces the following output:

123456789 squared = 15241578750190521
3 * test = 126
 */

 

相关标签: DynamicMethod