繁体   English   中英

使用反射发出通用方法在调用时引发异常

[英]Emitting Generic Method using Reflection Throws an Exception at Invoke

我正在尝试使用Reflection.Emit创建通用方法的简单示例,但是在调用Invoke时会导致异常,而我找不到问题。

public class Program
{
    public static void Main(string[] args)
    {
        AppDomain appDomain = AppDomain.CurrentDomain;
        AssemblyName name = new AssemblyName("MyAssembly") { Version = new Version("1.0.0.0") };
        AssemblyBuilder ab = appDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
        ModuleBuilder mb = ab.DefineDynamicModule("MyModule", "MyAssembly.dll");
        TypeBuilder tb = mb.DefineType("Widget", TypeAttributes.Public);

        // Define a method builder
        MethodBuilder methodBuilder = tb.DefineMethod("MyGenericMethod", MethodAttributes.Public | MethodAttributes.Static);

        // Get generic type parameter builders 
        GenericTypeParameterBuilder[] genericParams =
            methodBuilder.DefineGenericParameters("TKey", "TValue");

        methodBuilder.SetSignature(typeof(int), null, null,
            genericParams,
            null, null);
        methodBuilder.DefineParameter(1, ParameterAttributes.None, "key");
        methodBuilder.DefineParameter(2, ParameterAttributes.None, "val");

        ILGenerator gen = methodBuilder.GetILGenerator();
        MethodInfo writeLineStr = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) });
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Box, genericParams[0]);
        gen.Emit(OpCodes.Call, writeLineStr);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Box, genericParams[1]);
        gen.Emit(OpCodes.Call, writeLineStr);
        gen.Emit(OpCodes.Ret);

        Type t = tb.CreateType();
        MethodInfo genMeth = t.GetMethod("MyGenericMethod").MakeGenericMethod(typeof(string), typeof(int));
        genMeth.Invoke(null, new object[] { "NumberKey", 100 });
    }
}

调用genMeth.Invoke时,引发以下异常

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the t
arget of an invocation. ---> System.InvalidProgramException: Common Language Runtime detected an inv
alid program.
   at Widget.MyGenericMethod[TKey,TValue](TKey key, TValue val)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Bool
ean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Obje
ct[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder,
 Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at ReflectionEmitDemo14.Program.Main(String[] args) in d:\Projects\ReflectionEmitDemo\ReflectionE
mitDemo14\Program.cs:line 50

您的方法是静态的,具有两个参数:参数0和参数1。但是,在生成的IL代码中,您正在访问不存在的参数2。

另一个问题是,您试图将Int32值传递给需要String引用的方法。 选中两个参数,然后将它们传递给接受对象引用的WriteLine重载。

您还声明了返回Int32的方法,但是在返回之前没有将任何东西放在堆栈上。

尝试用C#编写方法,然后看一下C#编译器发出的IL(例如,使用ILspy)。 它看起来应该像这样:

ldarg.0
box !TKey
call void [mscorlib]System.Console::WriteLine(object)

ldarg.1
box !TValue
call void [mscorlib]System.Console::WriteLine(object)

ldc.i4.s 42
ret

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM