【问题标题】:Reflection Emit Derived by ObservableCollection由 ObservableCollection 派生的反射发射
【发布时间】:2016-12-27 06:01:44
【问题描述】:

我想创建带有反射发射的动态类型,例如:

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

非常感谢您的帮助!

【问题讨论】:

    标签: c# inheritance reflection collections typebuilder


    【解决方案1】:

    您的解决方案有几个问题:

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

    【讨论】:

    • 嗨安德烈,我创建了程序集并引用它来使用以使类型为“样本”,我在构建动态类型时遇到了一些错误,我在link 上提出了问题你能帮我出去吗这样的陷阱。提前致谢。
    • @JoonwK 我已经在那里添加了答案,请尝试一下stackoverflow.com/a/41371734/1942296
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 2016-10-12
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多