首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >实现IXmlSerializable的正确方式?

实现IXmlSerializable的正确方式?
EN

Stack Overflow用户
提问于 2008-11-10 23:19:10
回答 5查看 76.2K关注 0票数 159

一旦程序员决定实现IXmlSerializable,实现它的规则和最佳实践是什么?我听说GetSchema()应该返回nullReadXml应该在返回之前移动到下一个元素。这是真的吗?那么WriteXml呢--它应该为对象写一个根元素,还是假设根元素已经写好了?应该如何对待和写入子对象?

这是我现在所拥有的一个样本。我会在得到好的反馈后更新它。

代码语言:javascript
复制
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());
    }
}

相应的示例XML

代码语言:javascript
复制
<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>
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2008-11-11 05:14:51

是的,GetSchema() should return null

IXmlSerializable.GetSchema方法此方法是保留的,不应使用。实现IXmlSerializable接口时,应从此方法返回空值引用(在Visual Basic中为Nothing),如果需要指定自定义架构,则将XmlSchemaProviderAttribute应用于该类。

对于读和写,object元素已经被写入,所以您不需要在write中添加外部元素。例如,您可以开始读/写这两个文件中的属性。

对于write

XML您提供的实现应该写出对象的

表示。该框架编写一个包装器元素,并将XML编写器定位在其开始之后。您的实现可以编写其内容,包括子元素。然后,框架关闭包装器元素。

而对于read

ReadXml方法必须使用WriteXml方法写入的信息重新构造对象。

调用此方法时,读取器位于包装类型信息的元素的开头。也就是说,就在指示序列化对象开始的开始标记之前。当此方法返回时,它必须从头到尾读取整个元素,包括它的所有内容。与WriteXml方法不同,框架不会自动处理包装器元素。您的实现必须这样做。如果不遵守这些定位规则,可能会导致代码生成意外的运行时异常或损坏数据。

我承认这有点不清楚,但归根结底就是“你的工作就是结束包装器的Read() -element标签”。

票数 106
EN

Stack Overflow用户

发布于 2009-10-27 17:36:57

我写了一篇关于这个主题的文章和示例,因为MSDN文档到目前为止还很不清楚,你可以在web上找到的示例大多数时候都没有正确实现。

陷阱是除了Marc Gravell已经提到的对locale和空元素的处理。

http://www.codeproject.com/KB/XML/ImplementIXmlSerializable.aspx

票数 35
EN

Stack Overflow用户

发布于 2010-04-19 11:48:19

是的,整个事情有点像雷区,不是吗?Marc Gravell的答案几乎涵盖了这一点,但我想补充的是,在我参与的一个项目中,我们发现必须手动编写外部XML元素是相当尴尬的。这也导致相同类型的对象的XML元素名称不一致。

我们的解决方案是定义我们自己的IXmlSerializable接口,该接口派生自system接口,该接口添加了一个名为WriteOuterXml()的方法。正如您可以猜到的那样,此方法只需编写外部元素,然后调用WriteXml(),然后编写元素的末尾。当然,系统XML序列化程序不会调用此方法,因此它只在我们自己进行序列化时才有用,因此在您的情况下可能会有帮助,也可能没有帮助。类似地,我们添加了一个ReadContentXml()方法,它不读取外部元素,只读取其内容。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/279534

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档