当前位置:  开发笔记 > 编程语言 > 正文

正确的方法来实现IXmlSerializable?

如何解决《正确的方法来实现IXmlSerializable?》经验,为你挑选了3个好方法。

一旦程序员决定实施IXmlSerializable,实施它的规则和最佳实践是什么?我听说GetSchema()应该返回null并且ReadXml应该在返回之前移动到下一个元素.这是真的?那么WriteXml- 它应该为对象写一个根元素还是假设根已经写好了?儿童对象应如何处理和书写?

这是我现在拥有的样本.当我得到好的回复时,我会更新它.

public class MyCalendar : IXmlSerializable
{
    private string _name;
    private bool _enabled;
    private Color _color;
    private List _events = new List();


    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


    
    
    

Marc Gravell.. 95

是的,GetSchema()应该返回null.

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

对于读取和写入,已经编写了对象元素,因此您不需要在写入中添加外部元素.例如,您可以在两者中开始读/写属性.

对于写:

您提供的WriteXml实现应该写出对象的XML表示.该框架编写一个包装元素,并在XML编写器启动后定位它.您的实现可能会编写其内容,包括子元素.然后框架关闭包装元素.

而对于读:

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

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

我同意这有点不清楚,但它归结为"它是你的工作到Read()包装器的end-element标签".



1> Marc Gravell..:

是的,GetSchema()应该返回null.

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

对于读取和写入,已经编写了对象元素,因此您不需要在写入中添加外部元素.例如,您可以在两者中开始读/写属性.

对于写:

您提供的WriteXml实现应该写出对象的XML表示.该框架编写一个包装元素,并在XML编写器启动后定位它.您的实现可能会编写其内容,包括子元素.然后框架关闭包装元素.

而对于读:

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

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

我同意这有点不清楚,但它归结为"它是你的工作到Read()包装器的end-element标签".


感谢这些精度,MSDN中的示例代码非常缺乏用户,并且不清楚这一点.我被卡住了很多次,并且想知道Read/WriteXml的不对称行为.

2> jdehaan..:

我用样本写了一篇关于这个主题的文章,因为MSDN文档到目前为止还不太清楚,你在网上找到的例子大多数时候都是错误实现的.

陷阱是处理Marc Gravell已提到的区域和空元素.

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



3> EMP..:

是的,整个事情有点像雷区,不是吗?Marc Gravell的答案几乎涵盖了它,但我想补充一点,在我工作的项目中,我们发现手动编写外部XML元素非常尴尬.它还导致相同类型的对象的XML元素名称不一致.

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


使用C#3.0,您可以通过编写扩展方法来实现此目的,但这是一个有趣的想法.
推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有