假设您有两个类,一个继承另一个,并且需要使用XmlSerializer对子进行序列化/反序列化。但是,父级包含一个不可序列化的成员,比如字典。
public class Parent {
public Dictionary<string, int> dictionary;
}
父类是用于许多其他脚本的库。它无法修改。现在,子类只包含可序列化的成员:
public class Child : Parent {
[XmlElement]
public int foo;
}
尝试调用序列化程序时,收到错误消息,指出字典不可序列化。在尝试使用JSON进行序列化时,我设法以警告的价格逃脱。我刚刚创建了另一个具有相同名称和类型的成员,并使用了ScriptIgnore:
public class Child : Parent {
public int foo;
[ScriptIgnore]
public Dictionary<string, int> dictionary;
}
我在这里再次尝试了相同的技巧(通过使用XmlIgnore),但是效果不好,错误是一样的。我设法完成的唯一方法是创建单独的类,它们只提供xml de / serializing,然后将值复制回适当的位置。
有没有人知道更好的解决方法?我能否以任何方式让XmlSerializer忘记父词典?
答案 0 :(得分:4)
我会说的第一件事,并且总是说:如果序列化现有模型变得棘手 - 甚至远程尴尬,那么 停止这样做 。花2分钟创建一个单独的DTO模型,即仅为了序列化而创建的模型(实际上,甚至可能针对特定的序列化器定制)。现在你输入了正确的类型,正确的成员,正确的属性和正确的布局。您需要做的就是添加一些转换方法 - 静态转换运算符在这里工作得很好。所以我要说的是:创建一个ParentDto
和ChildDto
(你的名字可能会有所不同);它需要3分钟,而且效果很好。
现在,回到问题......
XmlSerializer
查看声明类的输入;对于属性和条件序列化,没有:此时我们无法将这些添加到类型模型中。但还有另一种选择 - 您可以使用XmlAttributeOverrides
假装词典成员上有[XmlIgnore]
。但是,一些重要的警告:
XmlAttributeOverrides
API有点使用(请参阅MSDN示例)XmlSerializer
这条路;基本上,如果你不这样做,每次new
一个序列化程序,并且程序集永不卸载时,它将创建一个新的动态程序集,所以你将出血记忆;请注意,简单用法(new XmlSerializer(someType)
等)具有内置缓存;但XmlAttributeOverrides
用法不 但是,与{em>创建基本DTO
相比,所有这些与XmlAttributeOverrides
混乱的工作要多得多。
使用XmlAttributeOverrides
:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Parent {
public Dictionary<string, int> 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
字段如何用于缓存序列化程序。
答案 1 :(得分:1)
您可以自己实施IXmlSerializable
并处理ReadXml(XmlReader reader)
和WriteXml(XmlWriter writer)
中的细节。如果您的类实现它们而不是生成自己的序列化器,XmlSerializer
将调用这些方法。
public class Child : Parent, IXmlSerializable
{
public int Foo { get; set; }
public Dictionary<string, int> 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();
}
}