I want to Serialize and DeSerialize an object which contains a Lazy
Collection
of some custom objects.
Normally everything works perfectly fine but, if namespaces of classes used for serialization are changed, then this issue occurs.
I have written a SerializationBinder
to point to right classes while deserializing. But for some reason, I am not getting deserialized values.
Following code snippet explains the problem that I am getting;
Classes used for Serialization:
namespace ConsoleApplication14
{
[Serializable]
public class MyInnerClass : ISerializable
{
private string _stringInInnerClassKey = "StringInInnerClass";
public string StringInInnerClass { get; set; }
public MyInnerClass() { }
private MyInnerClass(SerializationInfo info, StreamingContext context)
{
StringInInnerClass = info.GetString(_stringInInnerClassKey);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(_stringInInnerClassKey, StringInInnerClass);
}
}
[Serializable]
public class MyOuterClass : ISerializable
{
private string _collectionOfObjKey = "CollectionOfInnerObj";
public Lazy<Collection<MyInnerClass>> CollectionOfInnerObj { get; set; }
private MyOuterClass(SerializationInfo info, StreamingContext context)
{
if (info == null) throw new ArgumentNullException("serializationInfo");
CollectionOfInnerObj =
(Lazy<Collection<MyInnerClass>>)
info.GetValue(_collectionOfObjKey, typeof(Lazy<Collection<MyInnerClass>>));
}
public MyOuterClass() { }
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null) throw new ArgumentNullException();
info.AddValue(_collectionOfObjKey, CollectionOfInnerObj, typeof(Lazy<Collection<MyInnerClass>>));
}
}
}
Above same classes are used for Deserialization but only namespace is changed to ConsoleApplication14.OtherNamespace
For such Deserialization to work, I have used following SerializationBinder
class:
public class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
if (assemblyName.Equals(
"ConsoleApplication14, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"))
{
if (typeName.Equals("ConsoleApplication14.MyOuterClass"))
return typeof(ConsoleApplication14.OtherNamespace.MyOuterClass);
if (typeName.Equals("ConsoleApplication14.MyInnerClass"))
return typeof(ConsoleApplication14.OtherNamespace.MyInnerClass);
}
if (assemblyName.Equals("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"))
{
if (typeName.Equals(
"System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass, ConsoleApplication14, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"))
return typeof(Collection<ConsoleApplication14.OtherNamespace.MyInnerClass>);
if (typeName.Equals(
"System.Collections.Generic.List`1[[ConsoleApplication14.MyInnerClass, ConsoleApplication14, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"))
return typeof(List<ConsoleApplication14.OtherNamespace.MyInnerClass>);
if (typeName.Equals(
"System.Lazy`1[[System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass, ConsoleApplication14, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"))
return typeof(Lazy<Collection<ConsoleApplication14.OtherNamespace.MyInnerClass>>);
//I THINK, MAYBE THIS 'IF' CONDITION IS THE PROBLEM, BUT DONT KNOW HOW TO FIX THIS.
if (typeName.Equals(
"System.Lazy`1+Boxed[[System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass, ConsoleApplication14, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"))
return typeof(Lazy<Collection<ConsoleApplication14.OtherNamespace.MyInnerClass>>);
}
return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName));
}
}
Serialization and Deserialization of object of MyCustomClass
:
public static void Main(string[] args)
{
//----------------Object Creation----------------------
var objToSerialize = new MyOuterClass
{
CollectionOfInnerObj =
new Lazy<Collection<MyInnerClass>>(
() => new Collection<MyInnerClass>
{
new MyInnerClass
{
StringInInnerClass = "a"
},
new MyInnerClass
{
StringInInnerClass = "aa"
},
})
};
//------------------------------------------------------
//---------------------Serialization---------------------
using (var stream = File.Create("E:\\tempFile.tmp"))
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, objToSerialize);
stream.Close();
}
//------------------------------------------------------
//-------------------DeSerialization--------------------
using (var stream = File.OpenRead("E:\\tempFile.tmp"))
{
var binaryFormatter = new BinaryFormatter {Binder = new MyBinder()};
var objOfOtherNamespaceClass = (OtherNamespace.MyOuterClass) binaryFormatter.Deserialize(stream);
//Getting NullReferenceException when Value property of objOfOtherNamespaceClass.CollectionOfInnerObj is called
foreach (OtherNamespace.MyInnerClass stringVal in objOfOtherNamespaceClass.CollectionOfInnerObj.Value)
Console.WriteLine(stringVal.StringInInnerClass);
stream.Close();
}
//-----------------------------------------------------
}
I am getting NullReferenceException
when Value
property of deserialized Lazy object is called. (i.e. when objOfOtherNamespaceClass.CollectionOfInnerObj.Value
is called)
Please help me resolve this issue...
Problem is in line already highlighted by you
Please change this code to following
Type should be Boxed class, declared inside Lazy source code
Hope this help.