我有一个需要自定义序列化程序的类。我有时会在一个列表中使用这个类,我也想序列化它。其中一些元素将为空。
我可以让序列化工作:
<MyData xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Fractions>
<Frac>1/2</Frac>
<Frac xsi:nil="true" />
<Frac xsi:nil="true" />
<Frac>3/6</Frac>
</Fractions>
</MyData>
但是当像上面那样存在空元素时,反序列化不起作用。List<> 序列化程序似乎正在为一个元素调用 ReadXml() 而不是在列表中创建一个空元素。
当我运行我的示例时,反序列化版本是:
1/2
/
/
3/6
即在元素 1 和 2 中创建了一个 MyFrac 对象而不是 null。
我是否必须为 List 子类创建一个自定义序列化程序来解决这个问题,或者我是否缺少其他方法来获取反序列化时的空元素?如果自定义序列化程序,有什么最好的方法/代码?
我在下面有一个完整的示例,它显示了我当前的实现。
public class MyFrac : IXmlSerializable
{
public string N;
public string D;
public override string ToString()
{
return N + "/" + D;
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
return null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
{
if (reader.IsEmptyElement && reader.NodeType != XmlNodeType.EndElement)
{
reader.Read();
return;
}
reader.ReadStartElement();
string sfrac = reader.ReadString();
try
{
var m = Regex.Match(sfrac, @"(\d+)/(\d+)");
if (!m.Success)
throw new Exception(sfrac + " was not in the correct format");
N = m.Result("$1");
D = m.Result("$2");
}
finally
{
reader.ReadEndElement();
}
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteString(N + "/" + D);
}
}
public class MyData
{
[XmlArrayItem("Frac")]
public List<MyFrac> Fractions;
}
public static void Run()
{
var data = new MyData();
data.Fractions = new List<MyFrac>();
data.Fractions.Add(new MyFrac { N = "1", D = "2" });
data.Fractions.Add(null);
data.Fractions.Add(null);
data.Fractions.Add(new MyFrac { N = "3", D = "6" });
var serializer = new XmlSerializer(typeof(MyData));
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
serializer.Serialize(writer, data);
}
// Dump XML
Console.WriteLine(sb.ToString());
using (var reader = new StringReader(sb.ToString()))
{
var data2 = (MyData)serializer.Deserialize(reader);
Console.WriteLine(data2.Fractions[0]);
Console.WriteLine(data2.Fractions[1]);
Console.WriteLine(data2.Fractions[2]);
Console.WriteLine(data2.Fractions[3]);
}
}