Ошибка - метод не объявлен в определении обобщенного типа

211
29 июня 2018, 23:10

Я пытаюсь сгенерировать динамически следующую обобщенную функцию:

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"))); c сообщением:

The specified method cannot be dynamic or global and must be declared on a generic type definition

Я не могу понять, почему такой код падает в рантайме? Потому что я как понял, он должен работать, для я этого я специально использовал статический метод TypeBuilder.GetMethod

Answer 1

Проблема в том, что этот метод относится к типу List<T>, а не MyList<T>.

Когда вы ищите его в классе MyList<> (определение обобщенного типа), он оказывается найден в классе List<T> (инстанс обобщенного типа!). Чтобы такого не происходило - нужно искать метод в том классе где он и объявлен (тем более что такая проверка в TypeBuilder.GetMethod тоже есть, только до нее не доходит):

TypeBuilder.GetMethod(typeof(List<>).MakeGenericType(TInput), typeof(List<>).GetMethod("Add"))
READ ALSO
Как запустить анимацию по клику в Unity?

Как запустить анимацию по клику в Unity?

Есть 4 вида анимации для меню, созданы с помощью Anitamor в Unity

523
Преобразование штрих-кода в строку c#

Преобразование штрих-кода в строку c#

В общем я программно обрабатываю документы *xlsx и из нужных полей вынимаю нужные мне данные

221
Spawn клиента при подключении к серверу C# Unity3d

Spawn клиента при подключении к серверу C# Unity3d

Необходимо было сделать spawn игроков в Canvas через UnityNetworkРеализовал это следующим образом:

188