カスタムシリアライザーが必要なクラスがあります。また、このクラスをシリアル化したいリスト内で使用することもあります。これらの要素の一部は null になります。
シリアル化を機能させることができます:
<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>
ただし、上記のように null 要素が存在する場合、逆シリアル化は機能しません。List<> シリアライザーは、要素に対して ReadXml() を呼び出しているように見えますが、リストに null 要素を作成しているだけです。
私の例を実行すると、逆シリアル化されたバージョンは次のようになります。
1/2
/
/
3/6
つまり、要素 1 と 2 で null の代わりに MyFrac オブジェクトが作成されました。
これを回避するには、List サブクラスのカスタム シリアライザーを作成する必要がありますか?それとも、デシリアライズ時に null 要素を取得する他の方法がありませんか? カスタムシリアライザーの場合、最善のアプローチ/コードはありますか?
現在の実装を示す完全な例を以下に示します。
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]);
}
}