您的問題是,作爲documentation解釋,ReadXml()
必須消耗的包裝元素以及它的內容:
的ReadXml
方法必須使用的時候寫的信息重組的對象方法WriteXml
。
當調用此方法時,閱讀器位於包裝類型信息的開始標籤上。也就是說,直接在指示序列化對象開始的開始標籤上。 當此方法返回時,它必須從頭到尾讀取整個元素,包括其所有內容。與WriteXml
方法不同,框架不會自動處理包裝器元素。您的實施必須這樣做。未能遵守這些定位規則可能會導致代碼生成意外的運行時異常或損壞的數據。
MyClass.ReadXml()
不這樣做,這會導致無限循環時MyClass
對象不是序列作爲根元素。相反,你必須MyClass
看起來是這樣的:
public class MyClass : IXmlSerializable
{
public int A { get; set; }
public int B { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
/*
* https://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.readxml.aspx
*
* When this method is called, the reader is positioned at the start of the element that wraps the information for your type.
* That is, just before the start tag that indicates the beginning of a serialized object. When this method returns,
* it must have read the entire element from beginning to end, including all of its contents. Unlike the WriteXml method,
* the framework does not handle the wrapper element automatically. Your implementation must do so. Failing to observe these
* positioning rules may cause code to generate unexpected runtime exceptions or corrupt data.
*/
var isEmptyElement = reader.IsEmptyElement;
this.A = XmlConvert.ToInt32(reader.GetAttribute("A"));
this.B = XmlConvert.ToInt32(reader.GetAttribute("B"));
reader.ReadStartElement();
if (!isEmptyElement)
{
reader.ReadEndElement();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("A", XmlConvert.ToString(this.A));
writer.WriteAttributeString("B", XmlConvert.ToString(this.B));
}
}
現在你<MyClass>
元素很簡單,沒有嵌套或可選元素。對於更復雜的自定義序列化,有幾種策略可以用來保證您的ReadXml()
方法完全按照它應該的方式讀取,不多也不少。
首先,您可以撥打XNode.ReadFrom()
將當前元素加載到XElement
中。這需要更多的內存比直接從XmlReader
解析,但多更易於使用:
public class MyClass : IXmlSerializable
{
public int A { get; set; }
public int B { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
var element = (XElement)XNode.ReadFrom(reader);
this.A = (int)element.Attribute("A");
this.B = (int)element.Attribute("B");
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("A", XmlConvert.ToString(this.A));
writer.WriteAttributeString("B", XmlConvert.ToString(this.B));
}
}
其次,你可以使用XmlReader.ReadSubtree()
以確保所需的XML內容被消耗:
public class MyClass : IXmlSerializable
{
public int A { get; set; }
public int B { get; set; }
public XmlSchema GetSchema()
{
return null;
}
protected virtual void ReadXmlSubtree(XmlReader reader)
{
this.A = XmlConvert.ToInt32(reader.GetAttribute("A"));
this.B = XmlConvert.ToInt32(reader.GetAttribute("B"));
}
public void ReadXml(XmlReader reader)
{
// Consume all child nodes of the current element using ReadSubtree()
using (var subReader = reader.ReadSubtree())
{
subReader.MoveToContent();
ReadXmlSubtree(subReader);
}
reader.Read(); // Consume the end element itself.
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("A", XmlConvert.ToString(this.A));
writer.WriteAttributeString("B", XmlConvert.ToString(this.B));
}
}
最後幾點注意事項:
來源
2017-03-08 17:23:51
dbc