C# ILGenerator实例化对象并调用实例方法

C# ILGenerator实例化对象并调用实例方法,c#,ilgenerator,C#,Ilgenerator,我试图构造一个泛型类型的实例,并在该实例上调用一个方法。然后返回方法的结果 var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput)); il.DeclareLocal(genericType); var instanceMethod = genericType.GetMethod("MethodName", new Type[0]); il.Emit(OpCodes.Call, instanceM

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

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);
var genericType=typeof(genericType)。MakeGenericType(typeof(TOutput));
il.DeclareLocal(通用型);
var instanceMethod=genericType.GetMethod(“MethodName”,新类型[0]);
il.Emit(操作码.Call,实例方法);
发射(操作码Ret);
我不断收到“System.InvalidProgrammexecution”异常

GenericType类如下所示

public class GenericType<T>
{
    public T MethodName()
    {
        ...
    }
}
公共类GenericType
{
公共T方法名()
{
...
}
}
尝试以下代码:

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);
var-il=mbuilder.GetILGenerator();
var genericType=typeof(genericType).MakeGenericType(typeof(TOutput));
Emit(OpCodes.Newobj,genericType.GetConstructor(Type.EmptyTypes));
EmitCall(OpCodes.Callvirt,genericType.GetMethod(“MethodName”,Type.EmptyTypes),null);
发射(操作码Ret);

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

这里有一个例子…

复制的C#方法

publicstatictoutput DoWork()
{
var generic=新的GenericType();
var ret=generic.MethodName();
返回ret;
}
生成的IL

.method公共隐藏静态类App.TOutput
DoWork()cil管理
{
//代码大小15(0xf)
.maxstack 1
.locals init([0]类App.GenericType`1 generic,
[1] 类App.TOutput“ret”)
IL_0000:newobj实例无效类App.GenericType`1::.ctor()
IL_0005:stloc.0
IL_0006:ldloc.0
IL_0007:callvirt实例!0类App.GenericType`1::MethodName()
IL_000c:stloc.1
IL_000d:ldloc.1
IL_000e:ret
}//方法结束程序::DoWork
关于如何发出和调用此IL的示例

var retType=typeof(TOutput);
变量类型=类型(GenericType);
var genericType=type.MakeGenericType(retType);
var constructor=genericType.GetConstructor(Type.EmptyTypes);
var methodDef=genericType.GetMethod(“MethodName”,Type.EmptyTypes);
var newMethod=newdynamicmethod(“MyMethod”,retType,Type.EmptyTypes);
var生成器=newMethod.GetILGenerator();
生成器。DeclareLocal(genericType);
发电机。DeclareLocal(retType);
生成器.Emit(操作码.Newobj,构造函数);
生成器.Emit(操作码.Stloc_0);
生成器.Emit(操作码.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt,methodDef,null);
生成器.Emit(操作码.Stloc_1);
生成器.Emit(操作码.Ldloc_1);
生成器.Emit(操作码.Ret);
var ret=newMethod.Invoke(null,null);
控制台写入线(ret);//App.TOutput
支持课程

公共类GenericType,其中T:new()
{
公共T方法名()
{
返回新的T();
}
}
公共类投机者
{
}

一个简单的方法是找出正确的IL调用,即为您想要执行的操作编写C#代码,在发布模式下编译,然后使用ILDASM查看IL。您必须将目标对象的引用推送到堆栈上。因此,假设我想向方法“MethodName”传递一个局部参数。局部变量的作用域是生成IL的方法。局部变量名为“myLocal”,其作用域与genericType的作用域相同。@Mike您能更新一个问题或(甚至更好)创建一个新问题吗?这是新问题。谢谢你的专业知识。我正在完成解决方案并查看生成的IL代码,但这可能会更快。
public static TOutput DoWork()
{
    var generic = new GenericType<TOutput>();
    var ret = generic.MethodName();
    return ret;
}
.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
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
{
}