2013-07-23 2 views
0

Я пробую этот простой пример создания общего метода с использованием Reflection.Emit, но он вызывает исключение при вызове Invoke, и я не могу найти проблему.Исчезновение общего метода с использованием Reflection вызывает исключение при вызове

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 

ответ

3

Ваш метод является статическим и имеет два аргумента: аргумент 0 и аргумент 1. Но в сгенерированном коде IL вы обращаетесь аргумент 2, который не существует.

Другая проблема заключается в том, что вы пытаетесь передать значение Int32 методу, который ожидает ссылку на String. Вставьте оба аргумента и передайте их перегрузке WriteLine, которая принимает ссылку Object.

Вы также заявили, что ваш метод возвращает Int32, но перед возвратом вы ничего не кладете в стек.

Попробуйте написать метод в C#, а затем посмотрите, что ИЛ компилятор C# испускает (например, используя 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 
+0

В случае методов Ldarg_0 относится к «этому», а Ldarg_1 относится к первому параметру. Означает ли это, что в статических методах Ldarg_0 относится к первому параметру? – randacun

+0

Да, статические методы не имеют «этого» параметра. – dtb

+0

Изменен код, основанный на вашем комментарии, но исключение показывается. – randacun

Смежные вопросы