How to add an attribute to a property at runtime
C#AttributesC# Problem Overview
//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 });
Hi I am trying to add Validation attribute at runtime using the above code. However I am getting the below exception:
> Collection was of a fixed size
C# Solutions
Solution 1 - C#
Don't let someone tell you that you can't do it. You can run for president if you want :-)
For your convenience, this is a fully working example
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");
}
Solution 2 - C#
Use FastDeepCloner which I developed.
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>();
Solution 3 - C#
Sorry, I'm very late to the party. This is for those who might come here later. The top answer is awesome. Recently, a library has been developed, that abstracts away all of that complexity, and gives you something as simple as this:
var attributeType = typeof(CustomAAttribute);
var attributeParams = new object[] { "Jon Snow" };
var typeExtender = new TypeExtender("ClassA");
typeExtender.AddProperty("IsAdded", typeof(bool), attributeType, attributeParams);
To work with. details of how to install and use the library can be found here
Disclaimer: I developed this library and I've been using it for a lot of projects and it works like magic
Solution 4 - C#
It is not working because the FillAttributes
method expects a parameter of the IList type and you are passing an array. Below is the implementation of MemberDescriptor.FillAttributes:
protected virtual void FillAttributes(IList attributeList) {
if (originalAttributes != null) {
foreach (Attribute attr in originalAttributes) {
attributeList.Add(attr);
}
}
}
As you can see, FillAttributes
just fills the attributeList
parameter with all attributes of your property. And to make your code work, change the var attributes= new ValidationAttribute[]{attribute};
line with:
var attributes = new ArrayList { attribute };
This code has nothing with adding attributes to property of type at runtime. This is "adding attribute to the PropertyDescriptor
" extracted from type and has no sense unless you are trying to build a type at runtime which is based on an already existing type.
Solution 5 - C#
It is not possible to add Attributes in run-time. Attributes are static and cannot be added or removed.
Similar questions: