DataContractSerializer 未序列化继承 ISerialized 的类的成员

发布于 2024-08-02 13:42:42 字数 1666 浏览 5 评论 0原文

我有这个类:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Grouping
{
    [Serializable]
    public class Group<T> : HashSet<T>
    {
        public Group(string name)
        {
            this.name = name;
        }

        protected Group(){}

        protected Group(SerializationInfo info, StreamingContext context):base(info,context)
        {
            name = info.GetString("koosnaampje");
        }

        public override void GetObjectData(SerializationInfo info,StreamingContext context)
        {
            base.GetObjectData(info,context);
            info.AddValue("koosnaampje", Name);
        }

        private string name;
        public string Name
        {
            get { return name; }
            private set { name = value; }
        }
    }
}

由于它继承自 HashSet,因此它必须实现 ISerialized,因此需要实现受保护的构造函数和 GetObjectData 方法。 以前我用 BinaryFormatter 成功地序列化和反序列化了这个类。

因为我希望能够检查序列化器生成的输出,所以我想切换到 DataContractSerializer。

我编写了这个测试:

[TestMethod]
public void SerializeTest()
{
    var group = new Group<int>("ints"){1,2,3};
    var serializer = new DataContractSerializer(typeof (Group<int>));
    using (var stream=File.OpenWrite("group1.xml"))
    {
        serializer.WriteObject(stream,group);
    }
    using (var stream=File.OpenRead("group1.xml"))
    {
        group = serializer.ReadObject(stream) as Group<int>;
    }
    Assert.IsTrue(group.Contains(1));
    Assert.AreEqual("ints",group.Name);
}

测试失败,因为 Name 属性为 null! (尽管整数被正确地(反)序列化了) 怎么了?

编辑:它与名称支持字段是私有的无关。公开也有同样的结果。

I have this class:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Grouping
{
    [Serializable]
    public class Group<T> : HashSet<T>
    {
        public Group(string name)
        {
            this.name = name;
        }

        protected Group(){}

        protected Group(SerializationInfo info, StreamingContext context):base(info,context)
        {
            name = info.GetString("koosnaampje");
        }

        public override void GetObjectData(SerializationInfo info,StreamingContext context)
        {
            base.GetObjectData(info,context);
            info.AddValue("koosnaampje", Name);
        }

        private string name;
        public string Name
        {
            get { return name; }
            private set { name = value; }
        }
    }
}

As it inherits from HashSet it has to implement ISerializable, hence the protected constructor and GetObjectData method.
Formerly I serialized and deserialized this class succesfully with the BinaryFormatter.

Because I want to be able to inspect the output that is generated by the serializer I want to switch to the DataContractSerializer.

I wrote this test:

[TestMethod]
public void SerializeTest()
{
    var group = new Group<int>("ints"){1,2,3};
    var serializer = new DataContractSerializer(typeof (Group<int>));
    using (var stream=File.OpenWrite("group1.xml"))
    {
        serializer.WriteObject(stream,group);
    }
    using (var stream=File.OpenRead("group1.xml"))
    {
        group = serializer.ReadObject(stream) as Group<int>;
    }
    Assert.IsTrue(group.Contains(1));
    Assert.AreEqual("ints",group.Name);
}

The test fails because the Name property is null! (the integers are (de)serialized correctly though)
What is happening?

EDIT: it has nothing to do with the name backing field being private. Making it public has the same result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

仙女 2024-08-09 13:42:43

这与ISerialized无关; DataContractSerializer 根本不使用 ISerialized (它将使用 IXmlSerialized,但您不想这样做...)

大多数序列化程序,包括 XmlSerializer 和 DataContractSerializer(以及数据绑定),都将集合视为与实体不同的方式。它可以是其中之一,但不能同时是两者。因为它检测到它是一个“集合”,所以它序列化内容(即集合中的任何内容),而不是属性(名称等)。

您应该封装一个集合,而不是继承它。

还;要正确使用 DataContractSerializer,明智的做法是添加 [DataMember]/[DataContract] 属性。例如:

[Serializable, DataContract] // probably don't need [Serializable]
public class Group<T>
{
    [DataMember]
    public HashSet<T> Items { get; private set; }

    protected Group()
    {
        Items = new HashSet<T>();
    }
    public Group(string name) : this()
    {
        Name = name;
    }
    [DataMember]
    public string Name {get ;private set;}
}

This is nothing to do with ISerializable; DataContractSerializer simply doesn't use ISerializable (it will use IXmlSerializable, but you don't want to do that...)

Most serializers, including XmlSerializer and DataContractSerializer (and data-binding, for that matter), treat collections as different to entities. It can be one or the other, but not both. Because it detects that it is a "collection", it serializes the contents (i.e. whatever is in the set), not the properties (Name etc).

You should encapsulate a collection, rather than inherit it.

Also; to correctly use DataContractSerializer, it would be wise to add the [DataMember]/[DataContract] attributes. For example:

[Serializable, DataContract] // probably don't need [Serializable]
public class Group<T>
{
    [DataMember]
    public HashSet<T> Items { get; private set; }

    protected Group()
    {
        Items = new HashSet<T>();
    }
    public Group(string name) : this()
    {
        Name = name;
    }
    [DataMember]
    public string Name {get ;private set;}
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文