【问题标题】:ILGenerator instantiate object and call instance methodILGenerator 实例化对象并调用实例方法
【发布时间】:2017-07-26 17:41:43
【问题描述】:

我正在尝试构造一个泛型类型的实例并在该实例上调用一个方法。然后返回方法的结果。

var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.DeclareLocal(genericType);
var instanceMethod = genericType.GetMethod("MethodName", new Type[0]);
il.Emit(OpCodes.Call, instanceMethod);
il.Emit(OpCodes.Ret);

我不断收到“System.InvalidProgramExecution”异常。

GenericType 类看起来像这样

public class GenericType<T>
{
    public T MethodName()
    {
        ...
    }
}

【问题讨论】:

  • 找出正确的 IL 调用的一个简单方法是编写 C# 代码以执行您想要执行的操作,在发布模式下编译,然后使用 ILDASM 查看 IL。
  • 你必须将目标对象的引用压入栈中。

标签: c# ilgenerator


【解决方案1】:

确定您需要为特定函数发出什么 IL 的一种简单方法是手动编写要生成的代码,然后使用 ILDASM 查看编译器创建的 IL。

这是一个例子……

C# 方法复制...

public static TOutput DoWork()
{
    var generic = new GenericType<TOutput>();
    var ret = generic.MethodName();
    return ret;
}

生成的 IL...

.method public hidebysig static class App.TOutput 
DoWork() cil managed
{
    // Code size       15 (0xf)
    .maxstack  1
    .locals init ([0] class App.GenericType`1<class App.TOutput> generic,
            [1] class App.TOutput 'ret')
    IL_0000:  newobj     instance void class App.GenericType`1<class App.TOutput>::.ctor()
    IL_0005:  stloc.0
    IL_0006:  ldloc.0
    IL_0007:  callvirt   instance !0 class App.GenericType`1<class App.TOutput>::MethodName()
    IL_000c:  stloc.1
    IL_000d:  ldloc.1
    IL_000e:  ret
} // end of method Program::DoWork

有关如何发出和调用此 IL 的示例...

var retType = typeof(TOutput);
var type = typeof(GenericType<>);
var genericType = type.MakeGenericType(retType);
var constructor = genericType.GetConstructor(Type.EmptyTypes);
var methodDef = genericType.GetMethod("MethodName", Type.EmptyTypes);

var newMethod = new DynamicMethod("MyMethod", retType, Type.EmptyTypes);
var generator = newMethod.GetILGenerator();
generator.DeclareLocal(genericType);
generator.DeclareLocal(retType);
generator.Emit(OpCodes.Newobj, constructor);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, methodDef, null);
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ret);

var ret = newMethod.Invoke(null, null);
Console.WriteLine(ret); // App.TOutput

支持类...

public class GenericType<T> where T : new()
{
    public T MethodName()
    {
        return new T();
    }
}
public class TOutput
{
}

【讨论】:

    【解决方案2】:

    试试这个代码:

    var il = mbuilder.GetILGenerator();
    var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
    il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
    il.EmitCall(OpCodes.Callvirt, genericType.GetMethod("MethodName", Type.EmptyTypes), null);
    il.Emit(OpCodes.Ret);
    

    【讨论】:

    • 所以可以说我想将本地参数传递给方法“MethodName”。并且该局部变量的范围仅限于生成 IL 的方法。局部变量被命名为“myLocal”,其范围再次与 genericType 相同。
    • @Mike 你能更新一个问题或者(甚至更好)创建一个新问题吗?
    • 这是新问题。感谢您的专业知识。我正在努力完成解决方案并查看生成的 IL 代码,但这可能会更快。 stackoverflow.com/questions/45341097/…
    猜你喜欢
    • 2018-01-02
    • 2015-11-01
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    相关资源
    最近更新 更多