创建在两个对象之间重定向的代理类

时间:2018-10-31 22:35:03

标签: c# reflection.emit

这是我要实现的目标:在运行时,我想创建一个动态类,该动态类将覆盖任何T类。该想法是:生成的类将容纳3个类型为T的对象(我称之为原始对象) ,我将其称为“已修改”,其他我称为“活动”,并在这两者之间进行切换。

现在,我生成的类shoudl也扩展了T,而它的任何虚拟属性都将被覆盖(getter和setter),并将重定向到它拥有的Active对象的相同属性。

我的困难是:如何访问活动对象的属性?这是我的代码:

public static Type CompileResultType<T>()
    {
        //Gets Type builder that extends type T
        TypeBuilder tb = GetTypeBuilder<T>($"{typeof(T).Name}Proxy");
        ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        //Add Active field
        FieldBuilder activeFieldBuilder = tb.DefineField("Active", typeof(T), FieldAttributes.Public);

        //Add Original field
        FieldBuilder originalFieldBuilder = tb.DefineField("Original", typeof(T), FieldAttributes.Public);

        //Add Modified field
        FieldBuilder FieldBuilder = tb.DefineField("Modified", typeof(T), FieldAttributes.Public);

        //Get all public properties of type T
        var allProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

        //Get all virtual properties
        var filteredProperties = allProperties.Where(p => p.GetGetMethod().IsVirtual && p.GetSetMethod().IsVirtual);
        foreach (var property in filteredProperties)
            CreateProperty<T>(tb, property.Name, property.PropertyType, property);

        Type objectType = tb.CreateType();
        var teste = tb.GetFields();
        return objectType;
    }

    private static TypeBuilder GetTypeBuilder<T>(string typeSignature)
    {
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Mask.Builder");
        TypeBuilder tb = moduleBuilder.DefineType(typeSignature, TypeAttributes.Public | 
                                                                TypeAttributes.Class | 
                                                                TypeAttributes.AutoClass | 
                                                                TypeAttributes.AnsiClass | 
                                                                TypeAttributes.BeforeFieldInit | 
                                                                TypeAttributes.AutoLayout, typeof(T));
        return tb;
    }

    private static void CreateProperty<T>(TypeBuilder tb, string propertyName, Type propertyType, PropertyInfo activeProperty)
    {
        //THE PROBLEM LIES HERE: Trying to access the respective property of object Active, but doesn't work
        FieldBuilder fieldBuilder = tb.DefineField("Active." + propertyName, propertyType, FieldAttributes.Private);
        PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);

        //Create Getter that will retrieve "Active.PROPERTY"
        MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, propertyType, Type.EmptyTypes);
        ILGenerator getIl = getPropMthdBldr.GetILGenerator();
        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, fieldBuilder);
        getIl.Emit(OpCodes.Ret);


        //Create Setter that will write into "Active.PROPERTY"
        MethodBuilder setPropMthdBldr = tb.DefineMethod("set_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual, null, new[] { propertyType });

        ILGenerator setIl = setPropMthdBldr.GetILGenerator();
        Label modifyProperty = setIl.DefineLabel();
        Label exitSet = setIl.DefineLabel();

        setIl.MarkLabel(modifyProperty);
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, fieldBuilder);

        setIl.Emit(OpCodes.Nop);
        setIl.MarkLabel(exitSet);
        setIl.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getPropMthdBldr);
        propertyBuilder.SetSetMethod(setPropMthdBldr);
    }

0 个答案:

没有答案