使用属性覆盖属性的属性

10

我想找到一种改变属性序列化行为的方法。

假设我有一个这样的情况:

[Serializable]
public class Record
{
   public DateTime LastUpdated {get; set; }

   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   // other useful properties ...
}

现在我想序列化EmployeeRecord,但我不想序列化Record类中的LastUpdated属性。(但我希望在序列化Record时序列化LastUpdated)。

首先我尝试使用new关键字隐藏LastUpdated属性,然后添加XmlIgnore属性:

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   [XmlIgnore]
   public new DateTime LastUpdated {get; set; }
   // other useful properties ...
}

但那样做不起作用。然后我尝试将基类的LastUpdated属性设置为虚拟并覆盖它,保留该属性:

[Serializable]
public class Record
{
   public virtual DateTime LastUpdated {get; set; }

   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }

   [XmlIgnore]
   public override DateTime LastUpdated {get; set; }
   // other useful properties ...
}

这个也没有起作用。在这两个尝试中,LastUpdated 忽略了 XmlIgnore 属性并愉快地执行序列化操作。

有没有办法让我想做的事情发生?


你是如何进行序列化的?如果你使用二进制序列化,那么XmlIgnore属性就不会有太大作用。 - Chris Holmes
你可以使用NonSerialized属性进行二进制序列化。 - snarf
2个回答

17

首先,[Serializable]属性与XmlSerializer没有任何关系。这是一个误导。[Serializable]对System.Runtime.Serialization有意义,而XmlSerializer存在于System.Xml.Serialization中。如果您用[Serializable]修饰类和[XmlIgnore]修饰成员,则可能会使自己或其他读者混淆。

.NET中的XmlSerialization非常灵活。根据序列化是由您直接完成还是间接完成,比如由Web服务运行时完成,您有不同的控制方式。

一种选项是使用propertyNameSpecified模式来在XML序列化中打开或关闭属性。假设您有以下代码:

public class TypeA
{ 
  public DateTime LastModified;
  [XmlIgnore]
  public bool LastModifiedSpecified;
}

如果一个实例中的LastModifiedSpecified为false,则不会对该实例序列化LastModified字段。在您的类型的构造函数中,您可以将LastModifiedSpecified设置为始终为基类型中的true,并始终为派生类型中的false。实际的布尔值LastModifiedSpecified永远不会被序列化,因为它被标记为XmlIgnore。
这个小技巧在这里有记录。
您的另一个选择是使用XmlAttributeOverrides,这是一种动态提供XML序列化属性集(如XmlElementAttribute、XmlIgnoreAttribute、XmlRootAttribute等)的方法 - 在运行时动态提供这些属性给序列化程序。 XmlSerializer不再检查类型本身以获取这些属性,而只需遍历提供给其构造函数的覆盖属性列表即可。
    var overrides = new XmlAttributeOverrides();
    // ....fill the overrides here....
    // create a new instance of the serializer specifying overrides
    var s1 = new XmlSerializer(typeof(Foo), overrides);
    // serialize as normal, here.

这在这里有更详细的说明。

在您的情况下,您需要提供一个XmlIgnoreAttribute作为覆盖,但仅在序列化派生类型时使用。(或其他) 这仅在直接实例化XmlSerializer时才有效-当像Web服务一样隐式地进行序列化时,它将无效。

干杯!


哇,我以前从来没有听说过“指定模式”。简直太神奇了,完美解决问题! - Sailing Judo

8
我能想到的最好的方法是...
[Serializable]
public class Record
{
   public DateTime LastUpdated {get; set; }
   public virtual bool ShouldSerializeLastUpdated() {return true;}
   // other useful properties ...
}

public class EmployeeRecord : Record
{
   public string EmployeeName {get; set; }
   public override bool ShouldSerializeLastUpdated() {return false;}
   // other useful properties ...
}

基本上,XmlSerializer 遵循几种模式; public bool ShouldSerialize*() 和 public bool *Specified {get;set;} (请注意,您也应该使用 [XmlIgnore] 标记 *Specified...)。
这些模式并不十分优雅,但 XmlSerializer 只查看公共成员,因此您甚至无法隐藏它们(除非使用 [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)])。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接