Reputation: 869
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
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 signatureconstructor (SerializationInfo information, StreamingContext context)
. At deserialization time, the current constructor is called only after the data in theSerializationInfo
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:
IDictionary<TKey, TValue>
functionality and functionality of Dictionary<TKey, TValue>
does not satisfy your requirements than you should prefer to inherit IDictionary<TKey, TValue>
. 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