本文介绍了命名空间更改后的DataContractSerializer兼容性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要序列化的类.

I have a class need to be serialized.

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一起正常工作.序列化上下文之一,例如:

it is works fine with FromXML and ToXML. one of serialized context like:

<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类移至另一个外部"名称空间,现在将其序列化的上下文如下:

Later I need to move class EntityA to another namespace "outside", now the serialized context like:

<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).有人遇到过这个问题吗?有什么建议吗?

but now the serialized xml which created before change namespace can't be deserialized correctly. I guess this is because of for class "EntityA" changed namespace (xmlns:a added).does anybody run into the problem before? any suggestion?

推荐答案

您可以通过指定 [DataContract(Namespace =")] .这取决于您在保存任何xml代码之前设置该属性.

You can stop the namespace being added to the XML by specifying [DataContract(Namespace="")]. This relies on you setting that attribute BEFORE you save any xml code.

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

You can use this approach only if you have not already serialized any data, so this is the approach you would use when first designing a class to be serialized.

(如果您已经拥有必须处理的序列化数据,请参见下面我的回答的第二部分.)

(If you have already got serialized data that you must deal with, see the second part of my answer below.)

此代码示例在两个不同的命名空间( Test1 Test2 )中有两个名为 Demo 的类.

This code sample has the two classes called Demo in two different namespaces, Test1 and Test2.

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

We serialize the code using the class from one namespace, and deserialize it using the class from the other namespace:

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 =" 属性的数据,那么您将需要将适当的命名空间应用于新类:


If you have already serialized data without the Namespace="" attribute, then you will need instead to apply the appropriate namespace to the new class:

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

这篇关于命名空间更改后的DataContractSerializer兼容性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 12:58