【问题标题】:How to create a method at runtime using Reflection.emit如何在运行时使用 Reflection.emit 创建方法
【发布时间】:2010-08-23 20:34:09
【问题描述】:

我正在使用反射发射在运行时创建一个对象。我成功地创建了字段、属性和获取设置方法。 现在我想添加一个方法。为了简单起见,假设该方法只返回一个随机数。如何定义方法体?

编辑:

是的,我一直在查看 msdn 文档以及其他参考资料,并且开始对这些内容有所了解。 我看到上面的例子是如何添加和/或乘法的,但是如果我的方法正在做其他事情怎么办。我如何定义那个“东西” 假设我正在动态生成下面的类,我将如何创建 GetDetails() 方法的主体?

class TestClass
{
    public string Name  { get; set; }
    public int Size  { get; set; }

    public TestClass()
    {
    }

    public TestClass(string Name, int Size)
    {
        this.Name = Name;
        this.Size = Size;
    }

    public string GetDetails()
    {
        string Details = "Name = " + this.Name + ", Size = " + this.Size.ToString();
        return Details;
    }
}

【问题讨论】:

    标签: c#-4.0 reflection.emit


    【解决方案1】:

    您使用MethodBuilder 来定义方法。要定义方法体,您调用GetILGenerator() 来获取ILGenerator,然后调用Emit 方法来发出单独的IL 指令。 MethodBuilder 的 MSDN 文档中有一个示例,您可以在 Using Reflection Emit 页面上找到有关如何使用反射发射的其他示例:

    public static void AddMethodDynamically(TypeBuilder myTypeBld,
                                        string mthdName,
                                        Type[] mthdParams,
                                        Type returnType,
                                        string mthdAction)
    {
        MethodBuilder myMthdBld = myTypeBld.DefineMethod(
                                                mthdName,
                                                MethodAttributes.Public |
                                                MethodAttributes.Static,
                                                returnType,
                                                mthdParams);
        ILGenerator ILout = myMthdBld.GetILGenerator();
        int numParams = mthdParams.Length;
        for (byte x = 0; x < numParams; x++)
        {
            ILout.Emit(OpCodes.Ldarg_S, x);
        }
        if (numParams > 1)
        {
            for (int y = 0; y < (numParams - 1); y++)
            {
                switch (mthdAction)
                {
                    case "A": ILout.Emit(OpCodes.Add);
                        break;
                    case "M": ILout.Emit(OpCodes.Mul);
                        break;
                    default: ILout.Emit(OpCodes.Add);
                        break;
                }
            }
        }
        ILout.Emit(OpCodes.Ret);
    }
    

    听起来您正在寻找有关编写 MSIL 的资源。一个重要的资源是OpCodes 类,它对每条IL 指令都有一个成员。该文档描述了每条指令的工作原理。另一个重要资源是IldasmReflector。这些将让您看到编译代码的 IL,这将帮助您了解要编写的 IL。通过 Reflector 运行 GetDetailsMethod 并将语言设置为 IL 产生:

    .method public hidebysig instance string GetDetails() cil managed
    {
        .maxstack 4
        .locals init (
            [0] string Details,
            [1] string CS$1$0000,
            [2] int32 CS$0$0001)
        L_0000: nop 
        L_0001: ldstr "Name = "
        L_0006: ldarg.0 
        L_0007: call instance string ConsoleApplication1.TestClass::get_Name()
        L_000c: ldstr ", Size = "
        L_0011: ldarg.0 
        L_0012: call instance int32 ConsoleApplication1.TestClass::get_Size()
        L_0017: stloc.2 
        L_0018: ldloca.s CS$0$0001
        L_001a: call instance string [mscorlib]System.Int32::ToString()
        L_001f: call string [mscorlib]System.String::Concat(string, string, string, string)
        L_0024: stloc.0 
        L_0025: ldloc.0 
        L_0026: stloc.1 
        L_0027: br.s L_0029
        L_0029: ldloc.1 
        L_002a: ret 
    }
    

    要动态生成这样的方法,您需要为每条指令调用 ILGenerator.Emit:

    ilGen.Emit(OpCodes.Nop);
    ilGen.Emit(OpCodes.Ldstr, "Name = ");
    ilGen.Emit(OpCodes.Ldarg_0);
    ilGen.Emit(OpCodes.Call, nameProperty.GetGetMethod());
    // etc..
    

    您可能还想查找 MSIL 的介绍,例如:Introduction to IL Assembly Language

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-03
      • 1970-01-01
      • 2011-10-15
      • 2012-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-07
      相关资源
      最近更新 更多