我正在尝试动态生成以下通用函数:
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-带反射发射的方法)。对我来说,关键点是调用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
问题是这个方法是类型的
List<T>,不是MyList<T>。当您在一个类
MyList<>(泛型类型定义)中查找它时,它是在一个类中找到的List<T>(泛型类型实例!)。为了防止这种情况发生,您需要在声明它的类中查找方法(特别是因为它也有这样的检查TypeBuilder.GetMethod,但它没有到达它):