78
//Get PropertyDescriptor object for the given property name
var propDesc = TypeDescriptor.GetProperties(typeof(T))[propName];

//Get FillAttributes methodinfo delegate
var methodInfo = propDesc.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public |
                                                      BindingFlags.NonPublic)
    .FirstOrDefault(m => m.IsFamily || m.IsPublic && m.Name == "FillAttributes");

//Create Validation attribute
var attribute = new RequiredAttribute();
var  attributes= new ValidationAttribute[]{attribute};

//Invoke FillAttribute method
methodInfo.Invoke(propDesc, new object[] { attributes });

您好我正在尝试使用上面的代码在运行时添加验证属性。但是我收到以下异常:

集合是固定大小的

4

5 回答 5

195

不要让别人告诉你你做不到。如果你愿意,你可以竞选总统:-)

为了您的方便,这是一个完整的示例

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

    public string Value { get; set; }
}

public class SomeClass
{
    public string Value = "Test";
}

[TestMethod]
public void CanAddAttribute()
{
    var type = typeof(SomeClass);

    var aName = new System.Reflection.AssemblyName("SomeNamespace");
    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);

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

    Assert.AreEqual("Test", instance.Value);
    var attr = (SomeAttribute)instance.GetType()
        .GetCustomAttributes(typeof(SomeAttribute), false)
        .SingleOrDefault();
    Assert.IsNotNull(attr);
    Assert.AreEqual(attr.Value, "Some Value");
}
于 2014-06-25T15:40:26.220 回答
5

使用我开发的FastDeepCloner 。

public class test{
    public string Name{ get; set; }
}

var prop = DeepCloner.GetFastDeepClonerProperties(typeof(test)).First();
prop.Attributes.Add(new JsonIgnoreAttribute());
// now test and se if exist 
prop = DeepCloner.GetFastDeepClonerProperties(typeof(test)).First();
bool containAttr = prop.ContainAttribute<JsonIgnoreAttribute>()
// or 
JsonIgnoreAttribute myAttr = prop.GetCustomAttribute<JsonIgnoreAttribute>();
于 2017-09-16T17:04:42.417 回答
5

对不起,我参加晚会很晚了。这是给那些以后可能来这里的人的。最佳答案太棒了。最近,开发了一个库,它抽象了所有这些复杂性,并为您提供了一些简单的东西:

var attributeType = typeof(CustomAAttribute);
var attributeParams = new object[] { "Jon Snow" };
var typeExtender = new TypeExtender("ClassA");
typeExtender.AddProperty("IsAdded", typeof(bool), attributeType, attributeParams);

跟...共事。有关如何安装和使用该库的详细信息,请参见此处

免责声明:我开发了这个库,我已经在很多项目中使用它,它就像魔法一样工作

于 2020-12-18T15:14:06.003 回答
0

它不起作用,因为该FillAttributes方法需要 IList 类型的参数并且您正在传递一个数组。下面是MemberDescriptor.FillAttributes的实现:

protected virtual void FillAttributes(IList attributeList) { 
    if (originalAttributes != null) {
        foreach (Attribute attr in originalAttributes) {
            attributeList.Add(attr);
        } 
    }
}

如您所见,只需使用属性的所有属性FillAttributes填充参数。attributeList为了使您的代码正常工作,请更改以下var attributes= new ValidationAttribute[]{attribute};行:

var attributes = new ArrayList { attribute };

此代码与在运行时向类型属性添加属性无关。这是“将属性添加到PropertyDescriptor从类型中提取的”,除非您尝试在运行时构建基于现有类型的类型,否则没有任何意义。

于 2013-02-02T18:59:44.867 回答
-13

无法在运行时添加属性。属性是静态的,不能添加或删除。

类似的问题:

于 2013-02-02T17:05:08.027 回答