Cloning / Copying

I am creating a new type in a dynamic assembly from an existing type, but only with the selected properties:

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
}

All this works fine, but here I only create simple properties that just get or set a personal field.

I came across situations when I have a more complex property, for example, getter has something like: "A + B * C", where A, B and C are properties in the same class.

I tried to create a copy of getter in the CreatePropertyBase method as follows:

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

That obviously didn't work. :)

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

Thank.

+3
2

, IL , IL static PropertyInfo , . PropertyInfo, , , , .

, , ?

0
0

Source: https://habr.com/ru/post/1757357/


All Articles