首页 > 解决方案 > 如何在运行时修改“DataMember”属性的“Order”?

问题描述

我有一个数据成员,其中提到了订单值。我想根据选择查询中存在的参数顺序修改值。我无法在运行时设置数据成员的顺序值。

下面是我试过的代码:

[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);

我尝试了上面的代码来获取自定义属性和设置值,但它不起作用。是否可以在运行时更改属性值?

标签: c#wcfreflectionattributesdatamember

解决方案


不幸的是,没有办法Order在运行时更改参数的值。属性已在构建时评估并集成到编译代码中,因此您只能提供常量值。

最通用的方法是更改​​序列化代码,以便按请求的顺序对属性进行序列化,但这对于调整顺序来说太费力和风险了,至少恕我直言。

但是,如果您有一组非常有限的可能查询来为每个变体创建单独的方法,并且返回值具有根据需要调整值的不同类,那么您可以做什么。一种可能的方法是为所有对象创建一个基类。首先,您必须在基类中使用属​​性而不是字段。此外,关键字virtual为在派生类中被覆盖的属性做准备:

[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; }
}

对于每个变体,您将创建一个派生类,例如:

[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; }
}

变体 A 的方法将返回一个类型的对象,DetailsVariantA而不是Details.

请注意:正如您在示例中看到的那样,这种方法还涉及大量额外代码,因为每个变体都有另一个类。此外,它还引入了以后有人忘记将属性添加到所有派生类等的风险。
由于 WCF 主要用于在机器之间交换数据,并且数据通常不会被人类读取,因此从我的角度来看,我不会投入精力并引入这种仅更改顺序的风险。


推荐阅读