12

I need change attribute's parameter during runtime. I simplified my problem to simple example.

Attribute class:

    [AttributeUsage(AttributeTargets.Property)]
    public class MyAttribute : Attribute
    {
        public string Name { get; set; }
    }

Simple entity which has decorated properties with attributes:

    public class MyEntity
    {
        [MyAttribute(Name="OldValue1")]
        public string Data1{ get; set; }

        [MyAttribute(Name = "OldValue2")]
        public string Data2 { get; set; }
    }

I created instance of class MyEntity. I can change value of object's properties, but I can't change value of attribute’s property Name on object entity. Is it possible?

Value of property on object entity I can change with this part of code:

                entityProp.SetValue(entity,"NewData",null);

but I don't how change value of attribute's property Name on object entity

This does not work:

attProp.SetValue(attribute,"NewData",null);

Value of property Name is still original.

Here is all test code.

    [TestMethod]
    public  void Test()
    {
        var entity = new MyEntity
                         {
                             Data1 = "OldData",
                             Data2 = "OldData"
                         };

        PropertyInfo[] entityProps = entity.GetType().GetProperties();

        foreach (var entityProp in entityProps)
        {
            var attribute = Attribute.GetCustomAttribute(entityProp, typeof (MyAttribute)) as MyAttribute;

            if (attribute != null)
            {
                //get attribute's property NAME
                PropertyInfo attProp= attribute.GetType().GetProperty("Name");

                //get entity property value
                var propertyValue = entityProp.GetValue(entity, null);

                //get attribute’s property NAME value
                var atributeNameValue = attProp.GetValue(entity, null);

                TestContext.WriteLine(string.Format("property name:{0} property value: {1} : atribute name value: {2}\n", 
                    entityProp.Name, propertyValue, atributeNameValue)); 

                //change values
                entityProp.SetValue(entity,"NewData",null);

                //how can I change value of property Name on object entity ?
                attProp.SetValue(attribute,"NewData",null);
                
            }

        }

        TestContext.WriteLine(string.Format("After change\n"));

        foreach (var entityProp in entityProps)
        {
            var attribute = Attribute.GetCustomAttribute(entityProp, typeof(MyAttribute)) as MyAttribute;

            if (attribute != null)
            {

                PropertyInfo attProp = attribute.GetType().GetProperty("Name");

                var propertyValue = entityProp.GetValue(entity, null);
                var atributeNameValue = attProp.GetValue(entity, null);

                TestContext.WriteLine(string.Format("property name:{0} property value: {1} : atribute name value: {2}\n",
                    entityProp.Name, propertyValue, atributeNameValue));
            }
        }
    }

EDITED: I delete original post and added very simple clear sample. Sorry

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Mike
  • 441
  • 2
  • 5
  • 17

2 Answers2

13

You cannot change attributes at runtime. They are embedded into the metadata of the assembly. Your method is changing the internal state of a particular instance; but when you load the attribute again, you are getting a different instance.

David Nelson
  • 3,666
  • 1
  • 21
  • 24
  • 1
    @Mike I put a lot of effort into finding a solution to change attributes at runtime. Even with my 1337 haxxor skills, I found nothing. You may not like this answer, but unfortunately it is correct. – payo Apr 06 '12 at 18:09
  • You are right I spent one all day but could not find solution because this problem doesnt have solution. :( so attributes area readonly? – Mike Apr 06 '12 at 18:13
  • This is plain wrong. See: https://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime – Toastrackenigma Feb 10 '19 at 02:10
  • You flat out say that there is no way to do this, I disagree, as the answers on that other question that use reflection, etc, do actually work for a lot of these cases - they definitely solved my problem. While I don't disagree with the fact that attributes are part of the assembly, I disagree with broadly striking down the idea of changing them at runtime by saying it's impossible, when at least in some cases there are at least ways to do it (or at least something that **appears** like it does), especially if it could solve a problem like OP's. – Toastrackenigma Mar 14 '19 at 22:43
  • ***What isn’t generally realised is that you can change attribute instance values fairly easily at runtime. The reason is, of course, that the instances of the attribute classes that are created are perfectly normal objects and can be used without restriction*** https://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime – Kiquenet Jul 03 '20 at 19:54
  • @Toastrackenigma @Kiquenet the OP example clearly shows wanting to change the value of the attribute and have that change reflected *after* a subsequent call to `GetCustomAttribute`. This is not possible. The referenced answer merely shows changing the value of a particular loaded instance of the attribute; but the OP example already shows that, so I don't see how the referenced answer adds anything to the discussion. – David Nelson Jul 13 '20 at 22:27
  • @DavidNelson In many cases, the two solutions we link are "good enough" to do what people are after here. This is one of the top results when you search for this on Google -- the answers we have given are more to help those visitors then they are to help OP. Specifically, making a wrapper object and then changing the value of its field will provide the desired behavior for 99% of cases. It doesn't make too much sense to post that as an answer though, as it already exists on SO, so we link instead. – Toastrackenigma Jul 13 '20 at 22:41
5

This is not possible with reflection, as (as already noted) the metadata is fixed. It is, however, partly possible with TypeDescriptor, which allows adding and replacing of attributes at runtime, and providing complete alternative models (TypeDescriptionProvider, etc). This approach will not be respected by any code that uses reflection, but any code using TypeDescriptor (most typically, data-binding and other UI code) will notice the changes.

Note TypeDescriptor only really works with one of each attribute-type per typ/member; multi-instance attributes are not well supported.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Not possible? https://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime – Kiquenet Jul 03 '20 at 19:56
  • @kiquenet indeed, not possible; that other post covers a lot more reasons why it isn't possible, and doesn't present ant valid ways of doing it. What did I miss there? – Marc Gravell Jul 04 '20 at 06:30