【问题标题】:DataContractSerializer compatibility after namespace changed命名空间更改后的 DataContractSerializer 兼容性
【发布时间】:2014-03-31 16:23:27
【问题描述】:

我有一个类需要序列化。

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 类移动到“外部”的另一个命名空间,现在序列化的上下文如下:

<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。我猜这是因为类“EntityA”更改了命名空间(添加了 xmlns:a)。 有人遇到过这个问题吗?有什么建议吗?

【问题讨论】:

  • 在课程的两个版本中尝试[DataContract(Namespace="")]
  • @MatthewWatson 这也是一个重大改变;我想你的意思是Namespace="http://schemas.datacontract.org/2004/07/serializedobject"
  • @MarcGravell 不,我的意思是“”——我只是要添加一个代码示例。我在这里假设他尚未更改命名空间 - 即他可以在保留任何数据之前进行此更改。如果不是,那么我们必须将它应用于新类。我也会将其添加到我的回复中。
  • @MatthewWatson 我将这个问题解释为“我们已经开始持久化数据”,这就是为什么我倾向于保留现有行为/布局 - 但我同意 Namespace=""preferable 布局,在很多方面让我感到困扰的是,默认设置是如此可怕。与默认为空命名空间的XmlSerializer 形成对比。
  • @MarcGravell 你可能是对的——为了安全起见,我解决了这两种情况。 :)

标签: c# xml serialization


【解决方案1】:

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

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

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

此代码示例在两个不同的命名空间Test1Test2 中有两个名为Demo 的类。

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

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; }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    相关资源
    最近更新 更多