【问题标题】:C# Xml-Serializing a derived class using IXmlSerializableC# Xml-使用 IXmlSerializable 序列化派生类
【发布时间】:2009-02-09 12:11:42
【问题描述】:

我有一个与 XML 序列化兼容的基类和一个实现 IXmlSerializable 的派生类。

在这个例子中,基类确实实现了 IXmlSerializable:


using System.Diagnostics;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace XmlSerializationDerived
{
    public class Foo
    {
        public int fooProp;

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            fooProp = int.Parse (reader.ReadElementString ("fooProp"));
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString ("fooProp", fooProp.ToString ());
        }
    }

    public class Bar : Foo, IXmlSerializable
    {
        public new void ReadXml(XmlReader reader)
        {
            base.ReadXml (reader);
        }

        public new void WriteXml(XmlWriter writer)
        {
            base.WriteXml (writer);
        }

        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder ();
            XmlWriter writer = XmlWriter.Create (sb);

            Bar bar = new Bar ();
            bar.fooProp = 42;

            XmlSerializer serializer = new XmlSerializer (typeof (Bar));
            serializer.Serialize (writer, bar);

            Debug.WriteLine (sb.ToString ());
        }
    }
}

这会产生这个输出:

<?xml version="1.0" encoding="utf-16"?><Bar><fooProp>42</fooProp></Bar>

但是,我想使用一个实现 IXmlSerializable 的基类。这可以防止使用base.Read/WriteXml。结果将是:

<?xml version="1.0" encoding="utf-16"?><Bar />

有什么办法仍然可以得到想要的结果吗?

【问题讨论】:

    标签: c# xml serialization


    【解决方案1】:

    改进mtlung的回答,为什么不用XmlSerializer呢?您可以使用属性调整您的类,以便可以按照您想要的方式对其进行序列化,而且操作非常简单。

    using System.Xml.Serialization;
    
    ...
    
    [XmlRoot("someclass")]
    public class SomeClass
    {
        [XmlAttribute("p01")]
        public int MyProperty01
        {
            get { ... }
        }
    
        [XmlArray("sometypes")]
        public SomeType[] MyProperty02
        {
            get { ... }
        }
    
        [XmlText]
        public int MyProperty03
        {
            get { ... }
        }
    
        public SomeClass()
        {
        }
    }
    

    那么,序列化和反序列化就很简单了:

    void Save(SomeClass obj)
    {
        XmlSerializer xs = new XmlSerializer(typeof(SomeClass));
        using (FileStream fs = new FileStream("c:\\test.xml", ...))
        {
            xs.Serialize(fs, obj);
        }
    }
    
    void Load(out SomeClass obj)
    {
        XmlSerializer xs = new XmlSerializer(typeof(SomeClass));
        using (FileStream fs = new FileStream("c:\\test.xml", ...))
        {
            obj = xs.Deserialize(fs);
        }
    }
    

    生成的 XML 会是这样的:

    <someclass p01="...">
      <sometype>
        <!-- SomeType serialized objects as child elements -->
      </sometype>
      # value of "MyProperty03" as text #
    </someclass>
    

    这种方法更适用于“POCO”类,而且简单干净。您甚至不必使用属性,它们可以帮助您自定义序列化。

    【讨论】:

      【解决方案2】:

      " 这会阻止使用 base.Read/WriteXml。"

      通常,如果基类实现了IXmlSerializable,您可以将其设为virtual 方法,以便使用具体版本。通常,您还会使用显式实现(而不是公共属性) - 可能使用一些 protected virtual 方法来获取实现细节(尽管跟踪不同类中读取器/写入器的位置将是一场噩梦)。

      AFAIK,没有办法重复使用XmlSerializer 来写入 base 位,同时添加 derived 位。 IXmlSerializable 是全有或全无。

      【讨论】:

      • 来自 Java 并且序列化非常容易,听到这个我有点难过。实际上,我已经实现了 IXmlSerializable 的基类,我很幸运可以访问它。它有效,但有点疼,因为我正在编写不应该存在的代码。
      • 除非有人提出新方法,否则这是官方答案。
      【解决方案3】:

      为什么不在你的读/写函数中简单地使用 XmlSerializer?

      XmlSerializer s = new XmlSerializer(typeof(Foo));
      s.Serialize(writer, base);
      

      【讨论】:

      • 因为我不记得了,它必须手动序列化。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多