如何在运行时使用 Reflection.emit 创建方法 [英] How to create a method at runtime using Reflection.emit

查看:21
本文介绍了如何在运行时使用 Reflection.emit 创建方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm creating an object at runtime using reflection emit. I successfully created the fields, properties and get set methods. Now I want to add a method. For the sake of simplicity let's say the method just returns a random number. How do I define the method body?

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

Yes, I've been looking at the msdn documentation along with other references and I'm starting to get my head wrapped around this stuff. I see how the example above is adding and/or multplying, but what if my method is doing other stuff. How do I define that "stuff" Suppose I was generating the class below dynamically, how would I create the body of GetDetails() method?

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;
    }
}

推荐答案

您使用 MethodBuilder 来定义方法.要定义方法主体,请调用 GetILGenerator() 以获取 ILGenerator,然后调用Emit 方法来发出单独的 IL 指令.MethodBuilder 的 MSDN 文档中有一个示例,您可以在 使用反射发射 页面:

You use a MethodBuilder to define methods. To define the method body, you call GetILGenerator() to get an ILGenerator, and then call the Emit methods to emit individual IL instructions. There is an example on the MSDN documentation for MethodBuilder, and you can find other examples of how to use reflection emit on the Using Reflection Emit page:

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 指令都有一个成员.该文档描述了每条指令的工作原理.另一个重要的资源是 Ildasm反射器.这些将让您看到已编译代码的 IL,这将帮助您了解要编写的 IL.通过 Reflector 运行您的 GetDetailsMethod 并将语言设置为 IL 产生:


It sounds like you're looking for resources on writing MSIL. One important resource is the OpCodes class, which has a member for every IL instruction. The documentation describes how each instruction works. Another important resource is either Ildasm or Reflector. These will let you see the IL for compiled code, which will help you understand what IL you want to write. Running your GetDetailsMethod through Reflector and setting the language to IL yields:

.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:

To generate a method like that dynamically, you will need to call ILGenerator.Emit for each instruction:

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

您可能还想查找 MSIL 的介绍,例如:Introduction to MSILIL 汇编语言.

You may also want to look for introductions to MSIL, such as this one: Introduction to IL Assembly Language.

这篇关于如何在运行时使用 Reflection.emit 创建方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆