IgorStack
IgorStack

Reputation: 869

C# Deserialization exception on the object inherited from Dictionary

Why am I getting deserialization exception "The constructor to deserialize an object of type 'SerializeTest.TryMe' was not found" in the first implementation of class but not in the second?

1st implementation:

[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...
    ......
}

2nd implementation:

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

Serialization/deserialization code:

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

Also other then serialization issue when should I prefer to inherit IDictionary and when Dictionary?
Is there a canonical way/rule for this?

Upvotes: 3

Views: 889

Answers (1)

Iliar Turdushev
Iliar Turdushev

Reputation: 5213

Question:

Why am I getting deserialization exception "The constructor to deserialize an object of type 'SerializeTest.TryMe' was not found" in the first implementation of class but not in the second?

Answer:

Documentation of interface ISerializable says:

The ISerializable interface implies a constructor with the signature constructor (SerializationInfo information, StreamingContext context). At deserialization time, the current constructor is called only after the data in the SerializationInfo has been deserialized by the formatter.

(Let's call constructor (SerializationInfo information, StreamingContext context) a deserialization constructor.)

So from documentation we know that for classes that implement ISerializable a deserialization constructor is mandatory.

Class Dictionary<TKey, TValue> implements ISerializable and your class TryMe (from the second sample) inherits Dictionary<TKey, TValue>. During deserialization deserializer considers TryMe as a class that implements ISerializable and looks for deserialization constructor. Deserializer cannot find it and throws exception.

Interface IDictionary<TKey, TValue> does not implement ISerializable therefore deserialization constructor is not needed. In this case TryMe can be deserialized without deserialization constructor. Exception is not thrown.


Question:

Also other then serialization issue when should I prefer to inherit IDictionary and when Dictionary?

Is there a canonical way/rule for this?

Answer:

For serialization it is possible to inherit either Dictionary<TKey, TValue> or IDictionary<TKey, TValue>. But if you inherit Dictionary<TKey, TValue> a deserialization constructor must be added to your class.

When should you prefer to inherit IDictionary<TKey, TValue> and when Dictionary<TKey, TValue>? It depends on the problem you solve. In general we can consider two cases:

  1. If you need to implement a class with custom IDictionary<TKey, TValue> functionality and functionality of Dictionary<TKey, TValue> does not satisfy your requirements than you should prefer to inherit IDictionary<TKey, TValue>.
  2. If functionality of Dictionary<TKey, TValue> satisfy your requirements and, optionally, you need to change or add to it you own functionality than you should prefer to inherit Dictionary<TKey, TValue>.

If you implement IDictionary<TKey, TValue> by delegating appropriate methods to Dictionary<TKey, TValue> like in you first sample that it likely that you don't need to implement IDictionary<TKey, TValue>. In this case you should inherit Dictionary<TKey, TValue>.

// 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.
}

Upvotes: 3

Related Questions