2016-12-27 4 views
1

ich mit refelction dynamischen Typ erstellen möchten emittieren wie:Reflection Emit Abgeleitet von 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; 
    } 
} 

Der Code, den ich konnte nicht abgeschlossen ist dies wie:

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"); 

Ihre Hilfe wäre viel geschätzt !!

Antwort

2

Ihre Lösung hat mehrere Probleme:

  • AssemblyBuilderAccess sollte RunAndSave sein Typ-Instanz erstellen Objekte in der Laufzeit zu ermöglichen.
  • Sie müssen Körper für Konstruktor angeben.
  • Im Konstruktorkörper sollten Sie den Basistyp (ObservableCollection) Konstruktor aufrufen.
  • Im Konstruktorkörper sollten Sie den Feldwert aus den Konstruktorparametern setzen.

Meine Lösung für dieses Problem mit beiden Konstrukteure ist so etwas wie folgt aus:

 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

Dank Andrey Tretyak. Es ist großartig !!! –

+0

Hallo Andrey, ich habe Assembly erstellt und referenziert, um es zu konsumieren, um den Typ "Sample" zu machen, und ich habe einen Fehler beim Erstellen des dynamischen Typs bekommen, den ich Frage auf [link] (http://stackoverflow.com/questions/41357408/reflection -emit-how-to-build-constructor-for-this) Kannst du mir helfen, aus dieser Falle herauszukommen? Danke im Voraus. –

+0

@JoonwK Ich habe Antwort dort hinzugefügt, bitte versuchen Sie es http://StackOverflow.com/A/41371734/1942296 –

Verwandte Themen