无法反序列化惰性对象
Not able to deserialize Lazy object
我想序列化和反序列化包含一些自定义对象的 Lazy
Collection
的对象。
通常一切正常,但是,如果用于序列化的 classes 的命名空间发生更改,则会出现此问题。
我写了一个 SerializationBinder
在反序列化时指向右边的 classes。但出于某种原因,我没有得到反序列化的值。
以下代码片段解释了我遇到的问题;
类 用于序列化:
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>>));
}
}
}
以上相同的classes用于反序列化,但仅名称空间更改为ConsoleApplication14.OtherNamespace
为了使这种反序列化工作,我使用了以下 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));
}
}
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();
}
//-----------------------------------------------------
}
当调用反序列化的 Lazy 对象的 Value
属性 时,我得到 NullReferenceException
。 (即调用 objOfOtherNamespaceClass.CollectionOfInnerObj.Value
时)
请帮我解决这个问题...
问题在您已经突出显示的行中
//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>>);
请将此代码更改为以下内容
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 Type.GetType(typeName.Replace("ConsoleApplication14.MyInnerClass", "ConsoleApplication14.OtherNamespace.MyInnerClass"));
}
类型应为 Boxed class,在 Lazy 中声明 source code
public class Lazy<T>
{
#region Inner classes
/// <summary>
/// wrapper class to box the initialized value, this is mainly created to avoid boxing/unboxing the value each time the value is called in case T is
/// a value type
/// </summary>
[Serializable]
class Boxed
{
internal Boxed(T value)
{
m_value = value;
}
internal T m_value;
}
希望对您有所帮助。
我想序列化和反序列化包含一些自定义对象的 Lazy
Collection
的对象。
通常一切正常,但是,如果用于序列化的 classes 的命名空间发生更改,则会出现此问题。
我写了一个 SerializationBinder
在反序列化时指向右边的 classes。但出于某种原因,我没有得到反序列化的值。
以下代码片段解释了我遇到的问题;
类 用于序列化:
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>>));
}
}
}
以上相同的classes用于反序列化,但仅名称空间更改为ConsoleApplication14.OtherNamespace
为了使这种反序列化工作,我使用了以下 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));
}
}
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();
}
//-----------------------------------------------------
}
当调用反序列化的 Lazy 对象的 Value
属性 时,我得到 NullReferenceException
。 (即调用 objOfOtherNamespaceClass.CollectionOfInnerObj.Value
时)
请帮我解决这个问题...
问题在您已经突出显示的行中
//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>>);
请将此代码更改为以下内容
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 Type.GetType(typeName.Replace("ConsoleApplication14.MyInnerClass", "ConsoleApplication14.OtherNamespace.MyInnerClass"));
}
类型应为 Boxed class,在 Lazy 中声明 source code
public class Lazy<T>
{
#region Inner classes
/// <summary>
/// wrapper class to box the initialized value, this is mainly created to avoid boxing/unboxing the value each time the value is called in case T is
/// a value type
/// </summary>
[Serializable]
class Boxed
{
internal Boxed(T value)
{
m_value = value;
}
internal T m_value;
}
希望对您有所帮助。