将一个对象放在 ILGenerator 的堆栈顶部

Bas*_*wer 5 .net c# ilgenerator dynamic-code

我必须将一个对象的实例传递给一个函数,因此显然所有要作为参数的信息都将加载到评估堆栈中 这是我正在寻找的代码

someClass SomeObject = new someClass();

il.Emit(OpCodes.LoadObject, SomeObject);
il.Emit(OpCodes.CallVirt, MethodInfo Function);


public void Function(Object obj)
{
       Type type = typeof(obj);
       //do something w.r.t to the type
}
Run Code Online (Sandbox Code Playgroud)

我不需要任何存储在类中的信息只是类型,我不能使用任何原始类型来做出决定

最后我读到我可以使用一些操作码使用指针来加载类型......但我在这里完全迷失了,任何帮助或指向正确方向的指针都会很棒:)

[更新]

好吧,我找到了我自己问题的答案,尝试了它,它的工作原理不知道它是否正确,但我可以成功地创建一个对象并将其加载到堆栈中并将其传递给一个函数

ConstructorInfo ci = typeof(SomeClass).GetConstructor(System.Type.EmptyTypes);
IL.Emit(OpCodes.Newobj, ci);
IL.Emit(OpCodes.Call, SomeFunctionMethodInfo);
Run Code Online (Sandbox Code Playgroud)

SomeFunctionMethodInfo 是一个以 Object 作为参数的函数,我成功地将对象传递给函数,并且也可以操作它并将类作为对象返回。

我在任何地方都找不到对这个例子的引用,只是通过 MSDN 弄清楚了,我做错了什么还是有什么缺点?请专家们纠正或提供更好的答案

Mar*_*ell 5

你不能摘下参考了在稀薄的空气中IL,除非你的代码的引用作为IntPtr文本,在这种情况下:
        一。不要这样做
        B. 你需要固定
        c。不要这样做。

最好的方法取决于您正在编写的方法的签名。如果它是静态的并且没有参数......好吧,这有点棘手。亲自我倾向于将对象传递生成的方法,和具有该委托取它从那里需要任何外部数据。但另一种方法是生成一个class,并将该方法编写为访问类型字段的实例方法。

不同之处(因此我的偏好)是第一个需要(最多)object[]方法上的参数 - 您可以使用DynamicMethod; 第二个需要MethodBuilder, TypeBuilder, ModuleBuilder,AssemblyBuilder等,因此需要更多的工作。

我提到的原因object[]通常您希望生成的方法有一个共同的签名,即使它们需要不同的输入。这使您可以绑定到固定的委托类型并使用更快的Invoke执行(DynamicInvoke很慢)。

例如:

class SomeType { }
delegate void SomeDelegateType(params object[] args);
public class Program
{
    public static void Main()
    {
        var dn = new DynamicMethod("foo", (Type)null, new[] {typeof(object[])});
        var il = dn.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ldelem_Ref);
        il.EmitCall(OpCodes.Call, typeof(Program).GetMethod("Function"), null);
        il.Emit(OpCodes.Ret);
        var action = (SomeDelegateType)dn.CreateDelegate(typeof(SomeDelegateType));

        var obj = new SomeType();
        action(obj);
    }
    public static void Function(object obj)
    {
        Type type = obj.GetType();
        Console.WriteLine(type);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你不能有输入参数,那么你必须在你创建的类型上使用字段——这实际上正是你编写时编译器所做的(例如)

object someObj = ...
Action action = () => Function(someObj);
Run Code Online (Sandbox Code Playgroud)

这被创建为:

class <>somehorriblename {
    public object someObj;
    public void SomeGeneratedName() { Function(someObj); }
}
...
var captureClass = new <>somehorriblename();
captureClass.someObj = ...
Action action = captureClass.SomeGeneratedName;
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,应该可以使用普通(未固定)“GCHandle”对引用进行硬编码。唯一的问题是垃圾收集,但如果动态方法在应用程序域的生命周期内存在,那就没问题了。 (2认同)