2016-12-27 52 views
1

衍生我想創建一個動態類型與refelction發出這樣的:反射發出由的ObservableCollection

public class ObservableTestColleciton<T> : ObservableCollection<T> 
{ 
    public T Parent { get; set; } 
    public ObservableTestColleciton(T parent) 
    { 
     Parent = parent; 
    } 
    public ObservableTestColleciton(T parent, IEnumerable<T> source):base(source) 
    { 
     Parent = parent; 
    } 
} 

的代碼我不能完全是這樣的,如:

AppDomain myDomain = AppDomain.CurrentDomain; 
    AssemblyName myAsmName = new AssemblyName("AAB"); 
    AssemblyBuilder myAssembly =  myDomain.DefineDynamicAssembly(myAsmName,AssemblyBuilderAccess.Save); 
    ModuleBuilder myModule = myAssembly.DefineDynamicModule(myAsmName.Name,myAsmName.Name + ".dll"); 
    TypeBuilder myType = myModule.DefineType("ObservableTestCollection", TypeAttributes.Class | TypeAttributes.Public); 

    string[] typeParamNames = { "T" }; 
    GenericTypeParameterBuilder[] typeParams = myType.DefineGenericParameters(typeParamNames); 

    Type observableOf = typeof(ObservableCollection<>); 
    Type genOb = observableOf.MakeGenericType(typeParams[0]);   
    FieldBuilder myField = myType.DefineField("Parent", typeParams[0], FieldAttributes.Public); 
    ConstructorBuilder constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);   

    var type = myType.CreateType(); 
    var obj = Activator.CreateInstance(type); 
    myAssembly.Save("AAB.dll"); 

你的幫助會非常感謝!

回答

2

你的解決方案有幾個問題:

  • AssemblyBuilderAccess應該RunAndSave允許類型實例創建在運行時的對象。
  • 您需要爲構造函數指定主體。
  • 在構造函數體中,您應該調用基類型(ObservableCollection)構造函數。
  • 在構造函數體中,您應該從構造函數參數中設置字段值。

我對這個問題有兩個構造的解決辦法是這樣的:

 const string typeName = "ObservableTestCollection"; 
     const string fieldName = "Parent"; 
     const string assemblyName = "TestAssembly"; 
     const string assemblyFileName = assemblyName + ".dll"; 

     var domain = AppDomain.CurrentDomain; 
     var assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.RunAndSave); 
     var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, assemblyFileName); 

     var baseType = typeof(ObservableCollection<>); 
     var typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Class | TypeAttributes.Public, baseType); 
     var genericParameters = typeBuilder.DefineGenericParameters("T"); 
     var genericParameter = genericParameters.First(); 

     var fieldBuilder = typeBuilder.DefineField(fieldName, genericParameter, FieldAttributes.Public); 

     //First constructor ObservableTestColleciton(T parent) 
     var ctorParameters = new Type[] { genericParameter }; 
     var baseCtor = baseType.GetConstructor(Type.EmptyTypes); 
     var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters); 
     var generator = ctorBuilder.GetILGenerator(); 
     generator.Emit(OpCodes.Ldarg_0); // load this 
     generator.Emit(OpCodes.Call, baseCtor); //call base constructor 
     generator.Emit(OpCodes.Ldarg_0); // load this 
     generator.Emit(OpCodes.Ldarg_1); // load argument value 
     generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field 
     generator.Emit(OpCodes.Ret); //return 

     //Second constructor ObservableTestColleciton(T parent, IEnumerable<T> source):base(source) 
     var baseCtorParam = typeof(IEnumerable<>).MakeGenericType(genericParameter); 
     ctorParameters = new [] { genericParameter, baseCtorParam }; 
     baseCtor = baseType.GetConstructors() 
          .First(c => c.GetParameters().FirstOrDefault()?.ParameterType?.GetGenericTypeDefinition() == typeof(IEnumerable<>)); 

     ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, ctorParameters); 
     generator = ctorBuilder.GetILGenerator(); 
     generator.Emit(OpCodes.Ldarg_0); // load this 
     generator.Emit(OpCodes.Ldarg_2); // load second argument value 
     generator.Emit(OpCodes.Call, baseCtor); //call base constructor 
     generator.Emit(OpCodes.Ldarg_0); // load this 
     generator.Emit(OpCodes.Ldarg_1); // load first argument value 
     generator.Emit(OpCodes.Stfld, fieldBuilder); // store into Parent field 
     generator.Emit(OpCodes.Ret); //return 

     var genericType = typeBuilder.CreateType(); 
     var type = genericType.MakeGenericType(typeof(string)); 
     var fieldInfo = type.GetField(fieldName); 
     var obj1 = Activator.CreateInstance(type, "Parent1"); 
     Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj1)); //check that field value was set 
     var obj2 = Activator.CreateInstance(type, "Parent2", new List<string>()); 
     Console.WriteLine("Ctor1 field value :" + fieldInfo.GetValue(obj2)); 
     assemblyBuilder.Save(assemblyFileName); 
+0

感謝安德烈Tretyak。這太棒了! –

+0

嗨安德烈,我創建程序集並引用它消耗使類型「示例」,我在建立動態類型,我對[鏈接]發出問題有一些錯誤(http://stackoverflow.com/questions/41357408/reflection -emit-how-to-build-constructor-for-this)你能幫我擺脫這種陷阱嗎?提前致謝。 –

+0

@JoonwK我在那裏添加了答案,請嘗試一下http://stackoverflow.com/a/41371734/1942296 –