繁体   English   中英

使用Reflection.Emit以编程方式为现有类属性添加新属性

[英]Programmatically Adding new attribute for existing class property with Reflection.Emit

我正在尝试以编程方式在类成员的顶部添加新属性...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Test11
{

public class SomeAttribute : Attribute
{
    public SomeAttribute(string value)
    {
        this.Value = value;
    }

    public string Value { get; set; }
}


// for attribute to be injected the property should be "virtual"
public class ClassA
{
    public virtual int Value { get; set; }
}

public class Test
{
    public static void Func()
    {

        var type = typeof(ClassA);

        var aName = new System.Reflection.AssemblyName(Assembly.GetExecutingAssembly().GetName().Name);
        var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
        var mb = ab.DefineDynamicModule(aName.Name);
        var tb = mb.DefineType(type.Name + "Proxy", System.Reflection.TypeAttributes.Public, type);

        var attrCtorParams = new Type[] { typeof(string) };
        var attrCtorInfo = typeof(SomeAttribute).GetConstructor(attrCtorParams);
        var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { "Some Value" });
        tb.SetCustomAttribute(attrBuilder);




        PropertyInfo info = typeof(ClassA).GetProperty("Value", BindingFlags.Public | BindingFlags.Instance);

        PropertyBuilder newProp = tb.DefineProperty(info.Name, PropertyAttributes.None, info.PropertyType, Type.EmptyTypes);

        newProp.SetCustomAttribute(attrBuilder);


        //var tbValue = mb.DefineType(info.Name, System.Reflection.TypeAttributes.Public, type);

        FieldBuilder ValueField = tb.DefineField("_Value", typeof(string), FieldAttributes.Private);
        MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
        MethodBuilder ValuePropertyGet = tb.DefineMethod("get_Value", GetSetAttributes, typeof(string), Type.EmptyTypes);
        ILGenerator Generator = ValuePropertyGet.GetILGenerator();
        Generator.Emit(OpCodes.Ldarg_0);
        Generator.Emit(OpCodes.Ldfld, ValueField);
        Generator.Emit(OpCodes.Ret);

        MethodBuilder ValuePropertySet = tb.DefineMethod("set_Value", GetSetAttributes, null, new Type[] { typeof(string) });
        Generator = ValuePropertySet.GetILGenerator();
        Generator.Emit(OpCodes.Ldarg_0);
        Generator.Emit(OpCodes.Ldarg_1);
        Generator.Emit(OpCodes.Stfld, ValueField);
        Generator.Emit(OpCodes.Ret);


        newProp.SetSetMethod(ValuePropertySet);
        newProp.SetGetMethod(ValuePropertyGet);

        var newType = tb.CreateType();
        var instance = (ClassA)Activator.CreateInstance(newType);

        var attr = (SomeAttribute)instance.GetType().GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();

        var attr1 = (SomeAttribute)instance.Value.GetType().GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();

    }
}
}

这段代码为原始类创建了一个代理类。 它可以轻松地为整个类分配属性。

对于类属性,我可以用新的getter和setter替换属性,分配新的属性,但是对属性GetCustomAttribute的调用始终返回NULL

这行:

var attr1 = (SomeAttribute)instance.Value.GetType().GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();

正在寻找值类型(int)上的SomeAttribute属性,而不是新的Property。

本质上,你在做

typeof(int).GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();

由于明显的原因,该方法将返回null。

它应该是:

var attr1 = (SomeAttribute)instance.GetType().GetProperty(nameof(instance.Value), BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM