2010-08-23 47 views
7

我在运行时使用反射发射创建对象。我成功创建了字段,属性并获得了设置方法。 现在我想添加一个方法。为了简单起见,让我们说方法只是返回一个随机数。我如何定义方法体?如何在运行时使用Reflection.emit创建方法

编辑:

是的,我一直在寻找与其他参考一起MSDN文档,我开始我的头缠着这个东西。 我看到上面的例子是如何添加和/或multplying,但如果我的方法正在做其他的东西。我如何定义“东西” 假设我正在动态地生成下面的类,我将如何创建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; 
    } 
} 

回答

15

您使用MethodBuilder来定义方法。要定义方法体,请调用GetILGenerator()以获得ILGenerator,然后调用Emit方法发出单独的IL指令。有MSDN文档MethodBuilder上的例子,你可以找到如何使用反射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。通过反射运行你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