2014-12-02 5 views
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(); 
} 

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

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

что я делаю неправильно?

ответ

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 ' – leppie