【问题标题】:C# Deserialization exception on the object inherited from Dictionary从 Dictionary 继承的对象上的 C# 反序列化异常
【发布时间】:2020-03-24 02:28:26
【问题描述】:

为什么我在类的第一个实现中出现反序列化异常“找不到反序列化类型为'SerializeTest.TryMe'的对象的构造函数”,但在第二个实现中却没有?

第一次实现:

[Serializable]
public class TryMe : IDictionary<int, string>
{
    Dictionary<int, string> _dictionary = new Dictionary<int, string>();
    public TryMe() {}

    public IEnumerator<KeyValuePair<int, string>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }
    // all other IDictionary members are implemented below...
    ......
}

第二次实施:

[Serializable]
public class TryMe : Dictionary<int, string>
{
    public int Dummy { get; set; } = 5;
    public TryMe() {}
}

序列化/反序列化代码:

var tryMe = new TryMe();
tryMe[5] = "a"; tryMe[9] = "b"; tryMe[4] = "c";
using (var fs = new FileStream(@"D:\11.obj", FileMode.Create))
{
    var formatter = new BinaryFormatter();
    formatter.Serialize(fs, tryMe);
}

tryMe = null;
using (var fs = new FileStream(@"D:\11.obj", FileMode.Open))
{
    var formatter = new BinaryFormatter();
    tryMe = (TryMe)formatter.Deserialize(fs); // Exception here with 2nd implementation of TryMe!!
}

除了序列化问题之外,我应该何时更喜欢继承 IDictionary 以及何时应该继承 Dictionary
对此有规范的方式/规则吗?

【问题讨论】:

  • 这能回答你的问题吗? Constructor not found during deserialization?
  • @LouisGo:详细说明:我的问题是为什么我必须在一种情况下添加 ctor public TryMe(SerializationInfo info, StreamingContext context) : base(info, context) { } 而在另一种情况下不需要?
  • IDictionary 实现由类自己处理,而Dictionary 序列化实现不是由TryMe 完成的。如果TryMe 未指定,序列化程序如何知道将字典密钥对数据放在哪里?

标签: c# dictionary serialization deserialization


【解决方案1】:

问题:

为什么会出现反序列化异常“构造函数 未找到反序列化类型为“SerializeTest.TryMe”的对象” 类的第一个实现,但不是第二个?

答案:

接口ISerializable的文档说:

ISerializable 接口暗示了一个带有签名的构造函数 constructor (SerializationInfo information, StreamingContext context)。 在反序列化时,当前构造函数仅在 SerializationInfo 中的数据已被反序列化 格式化程序。

(我们称constructor (SerializationInfo information, StreamingContext context)为反序列化构造函数。)

所以从文档中我们知道,对于实现 ISerializable 的类,反序列化构造函数是强制性的。

Dictionary&lt;TKey, TValue&gt; 实现ISerializable 并且您的类TryMe(来自第二个示例)继承Dictionary&lt;TKey, TValue&gt;。在反序列化期间,反序列化器将TryMe 视为实现ISerializable 的类并寻找反序列化构造函数。反序列化程序找不到它并抛出异常。

接口IDictionary&lt;TKey, TValue&gt; 没有实现ISerializable,因此不需要反序列化构造函数。在这种情况下,TryMe 可以在没有反序列化构造函数的情况下反序列化。不抛出异常。


问题:

除了序列化问题,我什么时候应该更喜欢继承 字典和什么时候字典?

对此有规范的方法/规则吗?

答案:

对于序列化,可以继承Dictionary&lt;TKey, TValue&gt;IDictionary&lt;TKey, TValue&gt;。但如果你继承Dictionary&lt;TKey, TValue&gt;,则必须将反序列化构造函数添加到你的类中。

你应该在什么时候继承IDictionary&lt;TKey, TValue&gt;,什么时候继承Dictionary&lt;TKey, TValue&gt;这取决于你解决的问题。一般我们可以考虑两种情况:

  1. 如果您需要实现具有自定义IDictionary&lt;TKey, TValue&gt; 功能的类并且Dictionary&lt;TKey, TValue&gt; 的功能不能满足您的要求,那么您应该更愿意继承IDictionary&lt;TKey, TValue&gt;
  2. 如果 Dictionary&lt;TKey, TValue&gt; 的功能满足您的要求,并且(可选)您需要更改或添加您自己的功能而不是继承 Dictionary&lt;TKey, TValue&gt;

如果您通过将适当的方法委托给Dictionary&lt;TKey, TValue&gt; 来实现IDictionary&lt;TKey, TValue&gt;,就像您在第一个示例中一样,您可能不需要实现IDictionary&lt;TKey, TValue&gt;。在这种情况下你应该继承Dictionary&lt;TKey, TValue&gt;

// Sample, when it is better to inherit Dictionary<TKey, TValue> 
// instead of implementing IDictionary<TKey, TValue>.
[Serializable]
public class TryMe : IDictionary<int, string>
{
    Dictionary<int, string> _dictionary = new Dictionary<int, string>();

    public IEnumerator<KeyValuePair<int, string>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    public string this[key]
    {
        get { return _dictionary[key]; }
    }

    // Other IDictionary<TKey, TValue> members are implemented the same way.
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多