C# 实现IXmlSerializable的正确方法?
一旦程序员决定实现C# 实现IXmlSerializable的正确方法?,c#,xml,xml-serialization,C#,Xml,Xml Serialization,一旦程序员决定实现IXmlSerializable,实现它的规则和最佳实践是什么?我听说GetSchema()应该返回null,ReadXml应该在返回前移动到下一个元素。这是真的吗?那么关于WriteXml——它应该为对象写一个根元素,还是假设根元素已经被写了?如何处理和写入子对象 这是我现在拥有的一个样本。我会在收到好的回复后更新它 public class MyCalendar : IXmlSerializable { private string _name; priva
IXmlSerializable
,实现它的规则和最佳实践是什么?我听说GetSchema()
应该返回null
,ReadXml
应该在返回前移动到下一个元素。这是真的吗?那么关于WriteXml
——它应该为对象写一个根元素,还是假设根元素已经被写了?如何处理和写入子对象
这是我现在拥有的一个样本。我会在收到好的回复后更新它
public class MyCalendar : IXmlSerializable
{
private string _name;
private bool _enabled;
private Color _color;
private List<MyEvent> _events = new List<MyEvent>();
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyCalendar")
{
_name = reader["Name"];
_enabled = Boolean.Parse(reader["Enabled"]);
_color = Color.FromArgb(Int32.Parse(reader["Color"]));
if (reader.ReadToDescendant("MyEvent"))
{
while (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
{
MyEvent evt = new MyEvent();
evt.ReadXml(reader);
_events.Add(evt);
}
}
reader.Read();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("Name", _name);
writer.WriteAttributeString("Enabled", _enabled.ToString());
writer.WriteAttributeString("Color", _color.ToArgb().ToString());
foreach (MyEvent evt in _events)
{
writer.WriteStartElement("MyEvent");
evt.WriteXml(writer);
writer.WriteEndElement();
}
}
}
public class MyEvent : IXmlSerializable
{
private string _title;
private DateTime _start;
private DateTime _stop;
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "MyEvent")
{
_title = reader["Title"];
_start = DateTime.FromBinary(Int64.Parse(reader["Start"]));
_stop = DateTime.FromBinary(Int64.Parse(reader["Stop"]));
reader.Read();
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("Title", _title);
writer.WriteAttributeString("Start", _start.ToBinary().ToString());
writer.WriteAttributeString("Stop", _stop.ToBinary().ToString());
}
}
公共类MyCalendar:IXmlSerializable
{
私有字符串\u名称;
启用私有布尔;
私人色彩(u色),;
私有列表_事件=新列表();
公共XmlSchema GetSchema(){return null;}
公共void ReadXml(XmlReader)
{
if(reader.MoveToContent()==XmlNodeType.Element&&reader.LocalName==“MyCalendar”)
{
_名称=读卡器[“名称”];
_enabled=Boolean.Parse(读取器[“enabled”]);
_color=color.FromArgb(Int32.Parse(reader[“color”]);
if(reader.ReadToDescendant(“MyEvent”))
{
while(reader.MoveToContent()==XmlNodeType.Element&&reader.LocalName==“MyEvent”)
{
MyEvent evt=新的MyEvent();
ReadXml(reader);
_添加事件(evt);
}
}
reader.Read();
}
}
public void WriteXml(XmlWriter)
{
WriteAttributeString(“Name”,_Name);
WriteAttributeString(“Enabled”,_Enabled.ToString());
WriteAttributeString(“Color”,_Color.ToArgb().ToString());
foreach(MyEvent evt in_事件)
{
WriteStarteElement(“MyEvent”);
evt.WriteXml(编写器);
writer.writeedelement();
}
}
}
公共类MyEvent:IXmlSerializable
{
私有字符串\u标题;
私人日期时间(u start);;
私人日期时间站;
公共XmlSchema GetSchema(){return null;}
公共void ReadXml(XmlReader)
{
if(reader.MoveToContent()==XmlNodeType.Element&&reader.LocalName==“MyEvent”)
{
_标题=读者[“标题”];
_start=DateTime.FromBinary(Int64.Parse(reader[“start”]);
_stop=DateTime.FromBinary(Int64.Parse(reader[“stop”]);
reader.Read();
}
}
public void WriteXml(XmlWriter)
{
WriteAttributeString(“Title”,_Title);
WriteAttributeString(“Start”,_Start.ToBinary().ToString());
WriteAttributeString(“Stop”,_Stop.ToBinary().ToString());
}
}
对应的示例XML
<MyCalendar Name="Master Plan" Enabled="True" Color="-14069085">
<MyEvent Title="Write Code" Start="-8589241828854775808" Stop="-8589241756854775808" />
<MyEvent Title="???" Start="-8589241828854775808" Stop="-8589241756854775808" />
<MyEvent Title="Profit!" Start="-8589247048854775808" Stop="-8589246976854775808" />
</MyCalendar>
是,GetSchema()
IXmlSerializable.GetSchema此方法
方法是保留的,不应
用过。在实施
IXmlSerializable接口,您应该
返回一个空引用(在
VisualBasic),而不是,
如果无法指定自定义架构
如果需要,请应用
XmlSchemaProviderAttribute到
班级
对于读和写,object元素已经被写入,因此不需要在write中添加外部元素。例如,您可以开始读取/写入这两个属性中的属性
用于:
您需要的WriteXml实现
provide应该写出XML
对象的表示。这个
框架编写一个包装器元素并
将XML编写器放置在其
开始您的实现可以编写
它的内容,包括子
元素。然后框架关闭
包装器元素
以及:
ReadXml方法必须重新构造
使用以下信息创建对象:
是通过WriteXml方法编写的
调用此方法时,读取器
位于
元素,该元素为
你喜欢的类型。也就是说,就在
指示开始的开始标记
序列化对象的。当这
方法返回时,它必须已读取
从开始到结束的整个元素,
包括它的全部内容。不像
WriteXml方法,框架
不处理包装器元素
自动地您的实现
我们必须这样做。没有遵守这些规定
定位规则可能导致代码丢失
生成意外的运行时异常
或损坏数据
我同意这有点不清楚,但归根结底是“你的工作就是阅读包装的结束元素标签。”我写了一篇关于这个主题的文章,其中有一些例子,因为MSDN文档现在还不清楚,你在web上可以找到的例子大部分时间都没有正确实现 除了Marc Gravell已经提到的内容外,陷阱在于处理区域设置和空元素
是的,整个事情有点像雷区,不是吗Marc Gravell的回答几乎涵盖了这一点,但我想补充一点,在我参与的一个项目中,我们发现手动编写外部XML元素非常困难。它还导致相同类型的对象的XML元素名称不一致
我们的解决方案是定义我们自己的
IXmlSerializable
接口,该接口源自system one,它添加了一个名为WriteOuterXml()
的方法。正如您所猜测的,此方法只需编写外部元素,然后调用WriteXml()
,然后编写元素的结尾。当然,系统XML序列化程序不会调用此方法,因此它只有在我们自己进行序列化时才有用,因此在您的情况下可能有用,也可能无用。类似地,我们添加了一个ReadContentXml()
方法,该方法不读取外部元素,只读取其内容。如果您已经拥有类的XmlDocument表示形式,或者更喜欢使用XMLStru的XmlDocument方式
class ExampleBaseClass : IXmlSerializable {
public XmlDocument xmlDocument { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
xmlDocument.Load(reader);
}
public void WriteXml(XmlWriter writer)
{
xmlDocument.WriteTo(writer);
}
}
using System.Collections.Generic;
[System.Xml.Serialization.XmlRoot("dictionary")]
public partial class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, System.Xml.Serialization.IXmlSerializable
{
public virtual System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public virtual void ReadXml(System.Xml.XmlReader reader)
{
var keySerializer = new System.Xml.Serialization.XmlSerializer(typeof(TKey));
var valueSerializer = new System.Xml.Serialization.XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public virtual void WriteXml(System.Xml.XmlWriter writer)
{
var keySerializer = new System.Xml.Serialization.XmlSerializer(typeof(TKey));
var valueSerializer = new System.Xml.Serialization.XmlSerializer(typeof(TValue));
foreach (TKey key in Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
var value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
}
public SerializableDictionary() : base()
{
}
public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary)
{
}
public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer)
{
}
public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer)
{
}
public SerializableDictionary(int capacity) : base(capacity)
{
}
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer)
{
}
}