【问题标题】:Is the MSDN documentation for DataContractSerializer incorrect?DataContractSerializer 的 MSDN 文档是否不正确?
【发布时间】:2017-03-13 15:54:40
【问题描述】:

MSDN documentation for DataContractSerializer 包含以下语句:

只读字段、没有 get 或 set 方法的属性以及具有内部或私有 set 或 get 方法的属性不会序列化。此类属性将被忽略且不会引发异常,除非是 get-only 集合。

但是,我刚刚创建了以下程序,它可以很好地序列化只读、仅获取和私有集属性。是我误解了什么,还是文档不正确?

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string saveFile = "save.xml";
            Foo originalFoo = new Foo();
            SaveState(originalFoo, saveFile);
            Foo restoredFoo = LoadState<Foo>(saveFile);
        }
        public static void SaveState(Object o, string saveFile)
        {
            DataContractSerializer serializer = new DataContractSerializer(o.GetType());
            using (var writer = XmlWriter.Create(saveFile))
                serializer.WriteObject(writer, o);
        }
        public static T LoadState<T>(string loadFile)
        {
            using (var stream = new FileStream(loadFile, FileMode.Open))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(T));
                T obj = (T)serializer.ReadObject(stream);
                return obj;
            }
        }
    }

    [Serializable]
    public class Foo
    {
        private readonly int X;
        private int Y { get; }
        internal int Z { get; private set; }
        public Foo()
        {
            X = Y = Z = 10;
        }
    }
}

【问题讨论】:

  • 您使用了Serializable 属性,这意味着serialize everything
  • 该文档页面看起来不完整。在Types Supported by the Data Contract Serializer 中可以找到更完整的文档,其中指出支持的类型包括标有 SerializableAttribute 属性的 Types。 .NET Framework 基类库中包含的许多类型都属于这一类。 DataContractSerializer 完全支持 .NET Framework 远程处理、BinaryFormatter 和 SoapFormatter 使用的这种序列化编程模型,包括对 ISerializable 接口的支持。

标签: c# msdn datacontractserializer


【解决方案1】:

您使用了Serializable 属性,它指示序列化程序序列化所有内容。来自文档:

将 SerializableAttribute 属性应用于类型时,默认情况下会序列化所有私有和公共字段。您可以通过实现 ISerializable 接口来覆盖序列化过程,从而更精细地控制序列化。

如果您省略所有属性,则仅对公共属性和字段进行序列化,如文档中所述。例如,如果您添加 W 属性:

public class Foo
{
    private readonly int X;
    private int Y { get; }
    internal int Z { get; private set; }


    public int W { get; set; }
    public Foo()
    {
        X = Y = Z = 10;
    }
}

生成的文件将包含:

<?xml version="1.0" encoding="utf-8"?>
<Foo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/SO_Serializer">
    <W>15</W>
</Foo>

如果将DataContract属性添加到类中,则只有标有DataMember的成员会被序列化

【讨论】:

  • 您提供的信息很有启发性。谢谢你。但是,我仍然认为 MSDN 文档充其量是误导性的。它表明没有办法序列化只读属性,这根本不是真的。它没有提到[Serializable] 属性,让人相信没有解决这个缺点的方法。
  • 更糟糕的是,您提供给Serializable 文档的链接增加了混乱,因为它说具有该属性的类“不能被继承”。然而,我创建一个继承自 FooBar 类并没有问题,并且两者都被序列化了。
  • 文档没有这样说。他们说如果你使用适当的属性会发生什么。不过,您使用了通用的 Serializable 属性,其含义是“序列化所有内容”。
  • @kmote 不,它说SerializableClass 不能被继承。不能,因为它是密封的
  • 感谢您对 SerialzableClass 的澄清。我的错。至于您之前的评论,您提到了“适当的属性”。你是说[Serializable] 的使用适合DataContractSerializer?这是否意味着这是我应该避免的黑客行为?如果该属性不支持,那么您的论点是有道理的。但如果是,那么文档至少应该提到它,你不觉得吗?
【解决方案2】:

不,没有错!

只读字段、没有 get 或 set 方法的属性以及具有内部或私有 set 或 get 方法的属性不会序列化。此类属性将被忽略并且不会引发异常,除非是 get-only 集合。

应用 SerializableAttribute 属性,即使该类也实现了 ISerializable 接口来控制序列化过程。

将 SerializableAttribute 属性应用于类型时,默认情况下会序列化所有私有和公共字段。您可以通过实现 ISerializable 接口来覆盖序列化过程,从而更精细地控制序列化。

或者您可以通过将 NonSerializedAttribute 属性应用于字段来从序列化中排除字段。如果可序列化类型的字段包含特定于特定环境的指针、句柄或某些其他数据结构,并且无法在不同的环境中有意义地重构,则您可能希望将 NonSerializedAttribute 属性应用于该字段。

【讨论】:

  • 我对你投了反对票,因为你说我错了,尽管我发布了代码来证明不是这样,而且你没有提供我在原始帖子中已经引用的声明之外的任何见解。
  • @PanagiotisKanavos,如果这个答案解释了我使用的属性不是用来定义数据合同的,我就不会投反对票。就目前而言,它实际上没有提供任何有用的信息。如果它被编辑,我很乐意修改我的反对意见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 2013-02-19
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
相关资源
最近更新 更多