Ошибка «Метод не объявлен в определении универсального типа» - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь сгенерировать динамически такой метод:

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 голосов
/ 05 июня 2018

Я рекомендую вам всегда иметь под рукой декомпилятор при попытке создать IL.Вы почти у цели, но метод 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...