ILGenerator создает экземпляр объекта и вызывает метод экземпляра

Я пытаюсь создать экземпляр универсального типа и вызвать метод для этого экземпляра. Затем верните результат метода.

var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.DeclareLocal(genericType);
var instanceMethod = genericType.GetMethod("MethodName", new Type[0]);
il.Emit(OpCodes.Call, instanceMethod);
il.Emit(OpCodes.Ret);

Я продолжаю получать исключение System.InvalidProgramExecution.

Класс GenericType выглядит следующим образом

public class GenericType<T>
{
    public T MethodName()
    {
        ...
    }
}

2 ответа

Решение

Попробуйте этот код:

var il = mbuilder.GetILGenerator();
var genericType = typeof(GenericType<>).MakeGenericType(typeof(TOutput));
il.Emit(OpCodes.Newobj, genericType.GetConstructor(Type.EmptyTypes));
il.EmitCall(OpCodes.Callvirt, genericType.GetMethod("MethodName", Type.EmptyTypes), null);
il.Emit(OpCodes.Ret);

Простой способ выяснить, какой IL вам нужно выдать для конкретной функции, - написать код, который вы хотите сгенерировать вручную, а затем использовать ILDASM, чтобы увидеть IL, созданный компилятором.

Вот пример...

C# метод для дублирования...

public static TOutput DoWork()
{
    var generic = new GenericType<TOutput>();
    var ret = generic.MethodName();
    return ret;
}

Сгенерированный IL...

.method public hidebysig static class App.TOutput 
DoWork() cil managed
{
    // Code size       15 (0xf)
    .maxstack  1
    .locals init ([0] class App.GenericType`1<class App.TOutput> generic,
            [1] class App.TOutput 'ret')
    IL_0000:  newobj     instance void class App.GenericType`1<class App.TOutput>::.ctor()
    IL_0005:  stloc.0
    IL_0006:  ldloc.0
    IL_0007:  callvirt   instance !0 class App.GenericType`1<class App.TOutput>::MethodName()
    IL_000c:  stloc.1
    IL_000d:  ldloc.1
    IL_000e:  ret
} // end of method Program::DoWork

Пример того, как испустить и вызвать этот IL...

var retType = typeof(TOutput);
var type = typeof(GenericType<>);
var genericType = type.MakeGenericType(retType);
var constructor = genericType.GetConstructor(Type.EmptyTypes);
var methodDef = genericType.GetMethod("MethodName", Type.EmptyTypes);

var newMethod = new DynamicMethod("MyMethod", retType, Type.EmptyTypes);
var generator = newMethod.GetILGenerator();
generator.DeclareLocal(genericType);
generator.DeclareLocal(retType);
generator.Emit(OpCodes.Newobj, constructor);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.EmitCall(OpCodes.Callvirt, methodDef, null);
generator.Emit(OpCodes.Stloc_1);
generator.Emit(OpCodes.Ldloc_1);
generator.Emit(OpCodes.Ret);

var ret = newMethod.Invoke(null, null);
Console.WriteLine(ret); // App.TOutput

Поддержка классов...

public class GenericType<T> where T : new()
{
    public T MethodName()
    {
        return new T();
    }
}
public class TOutput
{
}
Другие вопросы по тегам