XmlSerializer – 忽略inheritance的不可序列化成员

假设您有两个类,一个inheritance另一个,并且需要使用XmlSerializer对子进行序列化/反序列化。 但是,父级包含一个不可序列化的成员,比如字典。

public class Parent { public Dictionary dictionary; } 

父类是用于许多其他脚本的库。 它无法修改。 现在子类只包含可序列化的成员:

 public class Child : Parent { [XmlElement] public int foo; } 

尝试调用序列化程序时,我收到一条错误,指出该字典不可序列化。 在尝试使用JSON进行序列化时,我设法以警告的价格逃脱。 我刚刚创建了另一个具有相同名称和类型的成员,并使用了ScriptIgnore:

 public class Child : Parent { public int foo; [ScriptIgnore] public Dictionary dictionary; } 

我在这里再次尝试了相同的技巧(通过使用XmlIgnore),但这不能很好地工作,错误是相同的。 我设法完成此操作的唯一方法是创建单独的类,它们只提供xml de / serializing,然后将值复制回适当的位置。

有没有人知道更好的解决方法? 我能否以任何方式让XmlSerializer忘记父词典?

我要说的第一件事,总是说:如果序列化现有模型变得棘手 – 甚至远程尴尬,那么就停止这样做 。 花2分钟创建一个单独的DTO模型,即仅为了序列化而创建的模型(实际上,甚至可能针对特定的序列化器进行定制)。 现在,您可以使用完全正确的类型,正确的成员,正确的属性和正确的布局。 您需要做的就是添加一些转换方法 – 静态转换运算符在这里工作得很好。 所以我要说的是:创建一个ParentDtoChildDto (你的名字可能会有所不同); 这需要3分钟,而且效果会非常好。

现在,回到问题……

XmlSerializer查看声明类的输入; 对于属性和条件序列化,没有:此时我们无法将这些添加到类型模型中。 但还有另一种选择 – 您可以使用XmlAttributeOverrides假装字典成员上有[XmlIgnore] 。 但是,一些重要的警告:

  • XmlAttributeOverrides API有点使用(参见MSDN示例)
  • 至关重要的是,您只需执行一次 ,然后存储并重新使用您以此方式创建的XmlSerializer ; 基本上,如果你这样做,它会在你每次new一个序列化程序时创建一个新的动态程序集,并且程序集永远不会卸载 ,所以你会出血记忆; 请注意, 简单的用法( new XmlSerializer(someType)等)有一个内置的缓存; 但XmlAttributeOverrides用法没有

但同样,所有这些与XmlAttributeOverrides混乱的工作要比创建基本DTO要多得多

使用XmlAttributeOverrides示例:

 using System; using System.Collections.Generic; using System.Xml.Serialization; public class Parent { public Dictionary WantToIgnoreThis { get; set; } } public class Child : Parent { public int Foo { get; set; } } static class Program { static readonly XmlSerializer customSerializer; static Program() { var xao = new XmlAttributeOverrides(); xao.Add(typeof(Parent), "WantToIgnoreThis", new XmlAttributes { XmlIgnore = true }); customSerializer = new XmlSerializer(typeof(Child), xao); } static void Main() { //var ser = new XmlSerializer(typeof(Child)); // ^^ this would fail customSerializer.Serialize(Console.Out, new Child { Foo = 123 }); } } 

请特别注意static字段如何用于缓存序列化程序。

您可以自己实现IXmlSerializable并处理ReadXml(XmlReader reader)WriteXml(XmlWriter writer)的细节。 如果您的类实现它们而不是生成自己的序列化程序, XmlSerializer将调用这些方法。

 public class Child : Parent, IXmlSerializable { public int Foo { get; set; } public Dictionary Dictionary { get; set; } public void WriteXml(XmlWriter writer) { writer.WriteStartElement("Foo"); writer.WriteValue(this.Foo); writer.WriteEndElement(); } void ReadXml(XmlReader reader) { var wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) { return; } reader.ReadStartElement("Foo"); this.Foo = reader.ReadContentAsInt(); reader.ReadEndElement(); } }