克隆/复制获得访问身体新型身体

2023-09-07 04:37:14 作者:夜长梦还多

我创造新的类型,从现有类型的动态组装,但只有选择的属性包括:

I'm creating new type in dynamic assembly from existing type, but with only selected properties to include:

public class EmitTest
{
    public Type Create(Type prototype, Type dynamicBaseType, List<string> includedPropertyList)
    {
        AssemblyName aName = new AssemblyName("DynamicAssembly");
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
                aName,
                AssemblyBuilderAccess.RunAndSave);

        ModuleBuilder modulBuilder = assemblyBuilder.DefineDynamicModule(aName.Name, aName.Name + ".dll");


        string typeName = string.Concat(prototype.Name, "_DynamicType_", Guid.NewGuid().ToString().Replace("-", string.Empty));

        TypeBuilder typeBuilder = modulBuilder.DefineType(
            typeName,
            TypeAttributes.Public, null, new Type[] { });

        foreach (string s in includedPropertyList)
        {
            PropertyInfo propertyInfo = prototype.GetProperty(s);

            if (propertyInfo != null && dynamicBaseType.GetProperty(s) == null)
            {
                CreateProperty(typeBuilder, propertyInfo);
            }
        }

        return typeBuilder.CreateType();
    }

    #region Property Creation

    private void CreateProperty(TypeBuilder typeBuilder, PropertyInfo propertyInfo)
    {
        PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(
            propertyInfo.Name,
            PropertyAttributes.HasDefault,
            propertyInfo.PropertyType,
            null);

        CreatePropertyBase(typeBuilder, propertyBuilder, propertyInfo);

        AddAttribute<BrowsableAttribute>(propertyBuilder, propertyInfo, CreatePropertyAttributeBrowsable);
        AddAttribute<DisplayNameAttribute>(propertyBuilder, propertyInfo, CreatePropertyAttributeDisplayName);          
    }

    private void CreatePropertyBase(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, PropertyInfo propertyInfo)
    {

        FieldBuilder fieldBuilder = typeBuilder.DefineField(
            string.Concat("m_", propertyInfo.Name),
            propertyInfo.PropertyType,
            FieldAttributes.Private);

        MethodAttributes getSetAttr = MethodAttributes.Public |
            MethodAttributes.SpecialName | MethodAttributes.HideBySig;


        MethodBuilder mbGetAccessor = typeBuilder.DefineMethod(
            string.Concat("get_", propertyInfo.Name),
            getSetAttr,
            propertyInfo.PropertyType,
            Type.EmptyTypes);

        ILGenerator mbGetIL = mbGetAccessor.GetILGenerator();
        mbGetIL.Emit(OpCodes.Ldarg_0);
        mbGetIL.Emit(OpCodes.Ldfld, fieldBuilder);
        mbGetIL.Emit(OpCodes.Ret);


        MethodBuilder mbSetAccessor = typeBuilder.DefineMethod(
            string.Concat("set_", propertyInfo.Name),
            getSetAttr,
            null,
            new Type[] { propertyInfo.PropertyType });

        ILGenerator mbSetIL = mbSetAccessor.GetILGenerator();           
        mbSetIL.Emit(OpCodes.Ldarg_0);
        mbSetIL.Emit(OpCodes.Ldarg_1);
        mbSetIL.Emit(OpCodes.Stfld, fieldBuilder);
        mbSetIL.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(mbGetAccessor);
        propertyBuilder.SetSetMethod(mbSetAccessor);
    }

    #endregion Property Creation

    #region Attribute Createion

    private void AddAttribute<T>(PropertyBuilder propertyBuilder, PropertyInfo propertyInfo, Action<PropertyBuilder, T> action)
        where T : Attribute
    {
        T attribute = ReflectionHelper.GetAttribute(propertyInfo, typeof(T), false) as T;

        if (attribute != null)
        {
            action(propertyBuilder, attribute);
        }
    }

    private void CreatePropertyAttributeBrowsable(PropertyBuilder propertyBuilder, BrowsableAttribute browsableAttribute)
    {
        ConstructorInfo myAttrCtor = typeof(BrowsableAttribute).GetConstructor(new Type[] { typeof(bool) });
        CustomAttributeBuilder myAttr = new CustomAttributeBuilder(myAttrCtor, new object[] { browsableAttribute.Browsable });
        propertyBuilder.SetCustomAttribute(myAttr);
    }

    private void CreatePropertyAttributeDisplayName(PropertyBuilder propertyBuilder, DisplayNameAttribute displayNameAttribute)
    {
        ConstructorInfo myAttrCtor2 = typeof(DisplayNameAttribute).GetConstructor(new Type[] { typeof(string) });
        CustomAttributeBuilder myAttr2 = new CustomAttributeBuilder(myAttrCtor2, new object[] { displayNameAttribute.DisplayName });
        propertyBuilder.SetCustomAttribute(myAttr2);
    }

    #endregion Attribute Createion
}

这一切的伟大工程,但在这里我只创建简单的属性,只是获取或设置私有字段。

This all works great, but here I'm creating only simple properties that just get or set private field.

我遇到了,我的吸气剂具有更复杂的特性,例如情况下,有这样的:A + B * C,其中A,B和C是同一类属性

我试图创造吸气的CreatePropertyBase方法复制这样的:

I tried creating copy of getter in CreatePropertyBase method like this:

        MethodBuilder mbNumberGetAccessor = typeBuilder.DefineMethod(
            string.Concat("get_", propertyInfo.Name),
            getSetAttr,
            propertyInfo.PropertyType,
            Type.EmptyTypes);       


        System.Reflection.MethodInfo mi = propertyInfo.GetGetMethod();
        byte[] body = mi.GetMethodBody().GetILAsByteArray();

        mbNumberGetAccessor.CreateMethodBody(body, body.Length);

这显然没有奏效。 :)

This obviously didn't work. :)

我的问题是:是否有可能复制get访问的引用了在同一类的其他属性的身体,如果可能的话怎么办呢。 我使用.NET 3.5 SP1

My question is: Is it possible to copy body of get accessor that has references to other properties in same class, and if possible how to do it. I'm using .NET 3.5 SP1

感谢。

推荐答案

您可以使用此助手(的 CIL阅读器)遍历的属性访问器机构和必要的修改,再重建

You can use this helper (CIL Reader) to traverse bodies of property accessors and reconstruct them with necessary modifications