Излучение неуниверсального типа из базового типа

1

Я пытаюсь создать не общий класс из родового родителя. Но я всегда получаю InvalidProgramException.

Мои базовые классы:

public interface IServiceType{}
public class ServiceType: IServiceType{}
public class EntityType{}
public class KeyType{}

public class Base<TService,TEntity, TKey>
{
    public Base(TService service)
    {
        Service = service;
    }

    public TService Service { get; set; }
}

Тип конструктора:

static Type CreateType(Type serviceType, Type entityType, Type keyType)
{
    var assemblyName = new AssemblyName("AssName");
    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    var moduleBuilder = assemblyBuilder.DefineDynamicModule("MainMod");

    var tb = moduleBuilder.DefineType(serviceType.Name.Substring(1)+entityType.Name, TypeAttributes.Public);

    var baseType = typeof (Base<,,>).MakeGenericType(serviceType, entityType, keyType);

    tb.SetParent(baseType);

    var baseCtor = baseType.GetConstructor(new [] {serviceType});
    if (baseCtor == null)
        throw new InvalidOperationException("Base type constuctor not found");

    var constuctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] {serviceType});

    var ilgen = constuctor.GetILGenerator();
    ilgen.Emit(OpCodes.Ldarg_0);
    ilgen.Emit(OpCodes.Call, baseCtor);
    ilgen.Emit(OpCodes.Ret);

  return tb.CreateType();
}

Когда я вызываю invoke, я получаю "Исключение было выбрано целью вызова".

void Main()
{
    var type = CreateType(typeof(IServiceType), typeof(EntityType), typeof(KeyType));
    var instance = Activator.CreateInstance(type, new ServiceType{});
    instance.Dump();
}

Что я делаю не так?

Теги:
generics
reflection.emit

1 ответ

4
Лучший ответ

Вам необходимо передать this и первый параметр

var ilgen = constuctor.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0); // this
ilgen.Emit(OpCodes.Ldarg_1); // 1st parameter
ilgen.Emit(OpCodes.Call, baseCtor);
ilgen.Emit(OpCodes.Ret);

Protip: Всегда сбрасывайте сгенерированный IL на сборку и проверяйте ее с помощью PEVerify.

  • 1
    использование tb.SetParent и определение базового типа в DefineType имеет тот же эффект. Предложенные вами команды Emit устранили проблему. Так что большое спасибо.
  • 0
    К сожалению, не заметил этого; p Это иногда необходимо, если у вас есть общее определение рекурсивного типа. Например, Foo : Something<Foo>

Ещё вопросы

Сообщество Overcoder
Наверх
Меню