0

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?

  • By reflection technical, we can merely get the value of the attribute, while we could not set the value of the attribute. At runtime, serialization order has been published in the service description info page (WSDL, metadata). I reckon it could not be achieved. – Abraham Qian Sep 05 '19 at 09:02

1 Answers1

0

Unfortunately, there is no way to change the value of the Order parameter at runtime. Attributes are already evaluated and integrated in the compiled code at build time so that you can only provide constant values.

The most generic way would be to change the serialization code so that the properties are serialized in the requested order, but this is way too much effort and risk for just adjusting the order, at least imho.

However, what you could do if you have a very limited set of possible queries to create separate methods for each variation and have different classes for the return value that adjust the values as required. One possible approach would be to create a base class for all objects. First, you'd have to use properties instead of fields in your base class. In addition, the keyword virtual prepares the properties for being overriden in a derived class:

[DataContract]
public class Details
{
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public virtual string id { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public virtual string name { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public virtual string creator { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public virtual string format { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public virtual string creationTime { get; set; }
}

For each variant, you'd create a derived class, like:

[DataContract]
public class DetailsVariantA : Details
{
    [DataMember(EmitDefaultValue = false, Order = 5)]
    public override string id { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 4)]
    public override string name { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 3)]
    public override string creator { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 2)]
    public override string format { get; set; }
    [DataMember(EmitDefaultValue = false, Order = 1)]
    public override string creationTime { get; set; }
}

The method for variant A would return an object of type DetailsVariantA instead of Details.

A word of caution: as you can see in the sample, this approach also involves a lot of extra code because you'd have another class per variant. Also, it introduces the risk that later on, someone forgets to add the properties to all derived classes and so on.
As WCF is primarily used to exchange data between machines and the data is usually not read by humans, from my point of view, I'd not invest the effort and introduce this risk for just changing the order.

Markus
  • 20,838
  • 4
  • 31
  • 55