我有一个我想要自定义序列化程序的类。我有时会在List中使用这个类,我也想序列化。其中一些元素将为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元素时,反序列化不起作用。列表&lt;&gt; serializer似乎在调用元素的ReadXml()而不是在列表中创建一个null元素。
当我运行我的示例时,反序列化的版本是:
1/2
/
/
3/6
即。在元素1和2中创建了MyFrac对象而不是null。
我是否必须为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]);
}
}
答案 0 :(得分:2)
您的问题是因为在反序列化期间发生XmlSerializer首先通过调用默认构造函数创建一个对象,然后调用 ReadXml 方法来设置属性值,以便 ReadXml 无法取消对象创建。是否有必要序列化空值以在xml中查看它?我的意思是你可以通过使用非List集合来避免这种情况。例如,创建自定义集合:
public class MyCollection : System.Collections.ObjectModel.Collection<MyFrac>
{
protected override void InsertItem(int index, MyFrac item)
{
if(item == null) return;
base.InsertItem(index, item);
}
protected override void SetItem(int index, MyFrac item)
{
if(item == null)
{
base.RemoveAt(index);
}
else
{
base.SetItem(index, item);
}
}
}
在 MyData 类中使用它:
public class MyData
{
[XmlArrayItem("Frac")]
public MyCollection Fractions;
}
然后序列化/反序列化按您的意愿工作:
public static void Main(string[] args)
{
var data = new MyData();
data.Fractions = new MyCollection();
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);
foreach (var element in data2.Fractions) {
Console.WriteLine(element);
}
}
Console.ReadLine();
}
序列化xml:
<?xml version="1.0" encoding="utf-16"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Fractions>
<Frac>1/2</Frac>
<Frac>3/6</Frac>
</Fractions>
</MyData>
输出:
<强> 1/2 强>
<强> 3/6 强>
<强>更新强>
好的,您需要使用自定义序列化规则。我们来实现它:
public class MyCollection<T> : Collection<T>, IXmlSerializable where T: class
{
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var serializer = new XmlSerializer(typeof(T));
var wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != XmlNodeType.EndElement)
{
if (reader.IsEmptyElement)
{
reader.Read();
Items.Add(null);
continue;
}
var item = (T)serializer.Deserialize(reader);
Items.Add(item);
}
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
var serializer = new XmlSerializer(typeof (T));
foreach (var myFrac in Items)
{
serializer.Serialize(writer, myFrac);
}
}
}
用法:
public class MyData
{
public MyCollection<MyFrac> Fractions;
}
class Program
{
static void Main(string[] args)
{
var data = new MyData();
data.Fractions = new MyCollection<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());
Trace.WriteLine(sb.ToString());
using (var reader = new StringReader(sb.ToString()))
{
var data2 = (MyData)serializer.Deserialize(reader);
foreach (var fraction in data2.Fractions)
{
var output = fraction == null ? "null" : fraction.ToString();
Console.WriteLine(output);
Trace.WriteLine(output);
}
}
Console.ReadLine();
}
}
输出xml:
<?xml version="1.0" encoding="utf-16"?>
<MyData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Fractions>
<MyFrac>1/2</MyFrac>
<MyFrac xsi:nil="true" />
<MyFrac xsi:nil="true" />
<MyFrac>3/6</MyFrac>
</Fractions>
</MyData>
输出数据:
<强> 1/2 强>
<强>空强>
<强>空强>
<强> 3/6 强>
我认为这就是你想要的。