"方法未在泛型类型定义中声明"错误

时间:2018-06-05 11:24:19

标签: c# reflection

我正在尝试生成这样的动态方法:

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

1 个答案:

答案 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);