即使使用XmlInclude

时间:2015-10-29 02:31:04

标签: c# serialization

如果我序列化派生类,即使使用XmlInclude属性,也无法反序列化基类。它失败了"没想到。"如果我使用与序列化数据相同的序列化程序实例,则可以正常工作。如果我创建一个新的序列化程序(就好像它在另一个进程中),它就会失败。

    [Serializable]
    [XmlInclude(typeof(D))]
    public class B
    {
        public string x { get; set; }
    }
    public class D : B
    {
        public string y { get; set; }
    }

... code snippet ....
    D x = new D();
    using (MemoryStream ms = new MemoryStream())
    {
        XmlSerializer serializer = new XmlSerializer(typeof(D));
        serializer.Serialize(ms, x);
        ms.Flush();

        ms.Seek(0, SeekOrigin.Begin);
        string responseBuffer = Encoding.ASCII.GetString(ms.GetBuffer());

        ms.Seek(0, SeekOrigin.Begin);
        serializer = new XmlSerializer(typeof(B));
        B x2 = (B)serializer.Deserialize(ms);
    }

正如我之前提到的,如果我使用原始序列化器(typeof(D)),它可以工作。如果我重新创建序列化器(typeof(B))。 在此先感谢您的帮助,

2 个答案:

答案 0 :(得分:2)

只有在希望通过XmlInclude属性自动反序列化任何/所有派生类时,才必须为基类型创建序列化程序。您的代码无效,因为您开始创建XmlSerializer serializer = new XmlSerializer(typeof(D));,它是子类型的序列化程序,并且没有基类的上下文。

稍后当您尝试使用类型B的Serializer反序列化此子xml时,它会失败,因为生成的序列化Xml没有基类型的上下文。

您必须创建类型B的Serializer,以便生成的Xml具有属性xsi:type,该属性指示XmlSerializer在反序列化期间实例化哪个子类型。

将您的代码更改为:

using (MemoryStream ms = new MemoryStream())
{
        XmlSerializer serializer = new XmlSerializer(typeof(B));
        serializer.Serialize(ms, x);
        ms.Flush();

        ms.Seek(0, SeekOrigin.Begin);
        string responseBuffer = Encoding.ASCII.GetString(ms.GetBuffer());

        ms.Seek(0, SeekOrigin.Begin);
        serializer = new XmlSerializer(typeof(B));
        B x2 = (B)serializer.Deserialize(ms);
}

早期代码中的Xml如下所示:

<D xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

然而,上面发布的代码将生成以下Xml:

<B xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="D" />

注意:节点本身现在是B,但附加属性xsi:type =“D”告诉XmlSerializer实际类型是什么。这是因为您在父节点中包含XmlInclude属性。

此外,用于生成/序列化xml到字符串MemoryStream类型不需要。通过ASCII GetString进行转换并不理想。您可以使用StringWriter和StringReader

您可以简化

D x = new D();
string xml;
using(var sw = new StringWriter())
{
    var serializer = new XmlSerializer(typeof(B));
    serializer.Serialize(sw, x);
    xml = sw.ToString();
}

B x2;
using(var sr = new StringReader(xml)) 
{
    var serializer = new XmlSerializer(typeof(B));
    x2 = serializer.Deserialize(sr) as B;
}
// if you check instance of x2 in debug, it will be of type D

答案 1 :(得分:0)

您需要让XmlSerializer了解所有需要反序列化的类型。

使用基类类型创建XmlSerializer,然后添加其他类型

示例:

var serializer = new XmlSerializer(typeof(B), new Type[] { typeof(D), typeof(C) });