命名空间更改后的DataContractSerializer兼容性

时间:2014-03-31 07:59:13

标签: c# xml serialization

我需要序列化一个类。

namespace serializedobject
{
[DataContract]
public class Class1
{
    string string1_;
    string string2_;
    EntityA entity_;

    [DataMember]
    public string string3
    {
        get { return string1_; }
        set { string1_ = value; }
    }

    [DataMember]
    public string string2
    {
        get { return string2_; }
        set { string2_ = value; }
    }
    [DataMember]
    public EntityA Entity
    {
        get { return entity_; }
        set { entity_ = value; }
    }

    public static Class1 FromXML(string desc)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            StreamWriter writer = new StreamWriter(ms);
            writer.Write(desc);
            writer.Flush();

            ms.Seek(0, 0);
            DataContractSerializer ser = new DataContractSerializer(typeof(Class1));
            return (Class1)ser.ReadObject(ms);
        }
    }

    public string ToXML()
    {
        using (MemoryStream ms = new MemoryStream())
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(Class1));
            ser.WriteObject(ms, this);
            ms.Seek(0, 0);
            StreamReader reader = new StreamReader(ms);
            return reader.ReadToEnd();
        }
    }
}

[DataContract]
public class EntityA
{
    string name_;
    [DataMember]
    public string Name
    {
        get { return name_; }
        set { name_ = value; }
    }
}
}

它适用于FromXML和ToXML。序列化上下文之一,如:

<Class1 xmlns="http://schemas.datacontract.org/2004/07/serializedobject"    xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Entity><Name>az</Name></Entity><string2 i:nil="true"/><string3>test</string3></Class1>

稍后我需要将类EntityA移动到另一个命名空间“outside”,现在是序列化的上下文,如:

<Class1 xmlns="http://schemas.datacontract.org/2004/07/serializedobject" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Entity xmlns:a="http://schemas.datacontract.org/2004/07/outside"><a:Name>az</a:Name></Entity><string2 i:nil="true"/><string3>test</string3></Class1>

但是现在在更改命名空间之前创建的序列化xml无法正确反序列化。我猜这是因为for class“EntityA”更改了命名空间(xmlns:添加了一个)。 以前有人遇到过这个问题吗?有什么建议吗?

1 个答案:

答案 0 :(得分:3)

您可以通过指定[DataContract(Namespace="")]来停止添加到XML的命名空间。这取决于您在保存任何xml代码之前设置该属性。

只有在尚未序列化任何数据时才能使用此方法,因此这是您在首次设计要序列化的类时使用的方法。

(如果您已经获得了必须处理的序列化数据,请参阅下面我的答案的第二部分。)

此代码示例在两个不同的名称空间DemoTest1中有两个名为Test2的类。

我们使用来自一个名称空间的类来序列化代码,并使用其他名称空间中的类对其进行反序列化:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;

namespace ConsoleApp1
{
    namespace Test1
    {
        [DataContract(Namespace="")]

        public sealed class Demo
        {
            [DataMember]
            public string Value { get; set; }
        }
    }

    namespace Test2
    {
        [DataContract(Namespace="")]

        public sealed class Demo
        {
            [DataMember]
            public string Value { get; set; }
        }
    }

    sealed class Program
    {
        private void run()
        {
            string filename = Path.GetTempFileName();
            var demo1 = new Test1.Demo {Value = "DEMO"};
            ToFile(filename, demo1);

            var demo2 = FromFile<Test2.Demo>(filename);
            Console.WriteLine(demo2.Value);
        }

        public static void ToFile(string filename, object obj)
        {
            DataContractSerializer serializer = new DataContractSerializer(obj.GetType());

            using (var streamWriter = File.CreateText(filename))
            using (var xmlWriter    = XmlWriter.Create(streamWriter, new XmlWriterSettings{Indent = true}))
            {
                serializer.WriteObject(xmlWriter, obj);
            }
        }

        public static T FromFile<T>(string filename)
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof(T));

            using (var textReader = File.OpenText(filename))
            using (var xmlReader  = XmlReader.Create(textReader))
            {
                return (T)serializer.ReadObject(xmlReader);
            }
        }

        [STAThread]
        static void Main(string[] args)
        {
            new Program().run();
        }
    }
}

如果您已经序列化了没有Namespace=""属性的数据,那么您需要将相应的命名空间应用于新类:

namespace Test1
{
    [DataContract]

    public sealed class Demo
    {
        [DataMember]
        public string Value { get; set; }
    }
}

namespace Test2
{
    // Note the namespace includes both nested namespaces, i.e. ConsoleApp1.Test1

    [DataContract(Namespace="http://schemas.datacontract.org/2004/07/ConsoleApp1.Test1")]

    public sealed class Demo
    {
        [DataMember]
        public string Value { get; set; }
    }
}