我正在尝试生成这样的动态方法:
MyList<T> CreateList<T>(T arg) => new MyList<T>(){arg};
以下是文档中的程序修改(来自https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-define-a-generic-method-with-reflection-emit的原始程序)。我只想调用基类Add
中定义的List
方法。我通过TypeBuilder.GetMethod
方法获取此方法信息:
public class MyList<T> : List<T>
{
}
public static void Main()
{
var asmName = new AssemblyName("DemoMethodBuilder1");
var demoAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
var demoModule = demoAssembly.DefineDynamicModule(asmName.Name, asmName.Name + ".dll");
var demoType = demoModule.DefineType("DemoType", TypeAttributes.Public);
var create_list_method = demoType.DefineMethod("CreateList", MethodAttributes.Public | MethodAttributes.Static);
var TInput = create_list_method.DefineGenericParameters(new string[] { "TInput" })[0];
var t_list_type = typeof(MyList<>).MakeGenericType(TInput);
create_list_method.SetParameters(new Type[] { TInput });
create_list_method.SetReturnType(t_list_type);
var ilgen = create_list_method.GetILGenerator();
ilgen.Emit(OpCodes.Newobj, TypeBuilder.GetConstructor(t_list_type, typeof(MyList<>).GetConstructors()[0]));
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, TypeBuilder.GetMethod(t_list_type, typeof(MyList<>).GetMethod("Add")));
ilgen.Emit(OpCodes.Ret);
demoType.CreateType();
demoAssembly.Save(asmName.Name + ".dll");
}
在ilgen.Emit(OpCodes.Callvirt, TypeBuilder.GetMethod(t_list_type, typeof(MyList<>).GetMethod("Add")));
处执行程序失败,并显示消息:
指定的方法不能是动态的或全局的,必须在泛型类型定义
上声明
我无法理解,为什么这样的代码会失败?至于我,我认为它应该工作 - 我故意使用静态方法TypeBuilder.GetMethod
答案 0 :(得分:4)
我建议您在尝试创建IL时始终拥有decompiler at hand。
您几乎就在那里,但Add
方法未在MyList
中定义,而在List
中定义,如您所见:
IL_0000: newobj instance void class MyList`1<!!T>::.ctor()
IL_0005: dup
IL_0006: ldarg.1
IL_0007: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<!!T>::Add(!0)
IL_000c: ret
这就是你必须告诉静态TypeBuilder
方法:
var add = TypeBuilder.GetMethod(typeof(List<>).MakeGenericType(TInput), typeof(List<>).GetMethod("Add"))
ilgen.Emit(OpCodes.Callvirt, add);