none
How to modify “Order” of “DataMember” attribute at runtime? RRS feed

  • Question

  • I have a datamembers where order values are mentioned. i want to modify the value according to the order of parameters present in select query. I am unable to set the order value for the datamember at runtime.

    Below is the code i tried :

    [DataContract]
        public class Details
        {
            [DataMember(EmitDefaultValue = false, Order = 1)]
            public string id;
            [DataMember(EmitDefaultValue = false, Order = 1)]
            public string name;
            [DataMember(EmitDefaultValue = false, Order = 1)]
            public string creator;
            [DataMember(EmitDefaultValue = false, Order = 1)]
            public string format;
            [DataMember(EmitDefaultValue = false, Order = 1)]
            public string creationTime;
        }
    
    Type type = executing.GetType("Details");
    FieldInfo[] properties = type.GetFields();
    properties[0].GetCustomAttributes(typeof(DataMemberAttribute), true).SetValue(2, 3);

    I tried the above code to get custom attribute and set value, but its not working. Is it possible to change attribute values during runtime?

    Thursday, September 5, 2019 7:18 AM

All replies

  • Hi Deepa,

    Thank you for posting here.

    We could achieve the value from the class by using the following code.

      [DataContract]
            public class Details
            {
                [DataMember(EmitDefaultValue = false, Order = 1)]
                public string id;
                [DataMember(EmitDefaultValue = false, Order = 1)]
                public string name;
                [DataMember(EmitDefaultValue = false, Order = 1)]
                public string creator;
                [DataMember(EmitDefaultValue = false, Order = 1)]
                public string format;
                [DataMember(EmitDefaultValue = false, Order = 1)]
                public string creationTime;
            }
            static void Main(string[] args)
            {
                Details d = new Details();
                Type type = d.GetType();
                FieldInfo[] properties = type.GetFields();
                var m = properties[0];
                var n = m.CustomAttributes;
                foreach (var item in n)
                {
                    foreach (var i in item.NamedArguments)
                    {
                        Console.WriteLine(i.TypedValue.Value);
                    }
                }
            }

    However, we could not set the value. If you want to know more about it, you could refer to the following link.

    Change custom attribute's parameter at runtime

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, September 5, 2019 8:42 AM
    Moderator
  • Firstly, this is a data contract and therefore I assume you have clients using it. It is a breaking change to alter the order of data members. So if you move members (just for your query) then you are breaking clients.

    I don't understand what the order of the contract has to do with the order of an arbitrary select query in your code. You shouldn't relate the 2. Data layout is not your data contract and should never be mixed. If you need some sort of mapping either use an intermediate object or apply a new attribute. For example the ColumnAttribute was added to .NET to support EF and it serves this purpose. 

    Attribute values are baked into the source code and cannot be changed at runtime. There is no way to make this work without recompiling your code. The attributes are metadata. The runtime caches this information when it is loaded and no amount of changing on your side will have any impact. This is by design.

    class Program
    {
        static void Main ( string[] args )
        {
            var instance = new MyData();
    
            var prop = instance.GetType().GetProperty(nameof(MyData.Name));
    
            //This clones the attribute from the metadata and returns it to you
            var attr = prop.GetCustomAttributes(false).OfType<MyAttribute>().FirstOrDefault();
                
            //Setting this only impacts your cloned copy, nobody else will ever see it
            attr.Id = 4;
    
            //Value is 4 because you changed it here but only for this cloned copy
            var currentId = attr.Id;
    
            //Getting the attribute again returns a clone of the original metadata, no way to change this
            var attr2 = prop.GetCustomAttributes(false).OfType<MyAttribute>().FirstOrDefault();
    
            //Value is 1 because it is baked into metadata, you cannot change this behavior
            var actualId = attr2.Id;
        }
    }
    
    class MyAttribute : Attribute
    {
        //This is not changeable at runtime
        public int Id { get; set; }
    }
    
    class MyData
    {
        [My(Id = 1)]
        public string Name { get; set; }
    }


    Michael Taylor http://www.michaeltaylorp3.net

    Thursday, September 5, 2019 2:00 PM
    Moderator