C# · 1月 28, 2022

c# – 无法反序列化Lazy对象

我想序列化和DeSerialize一个包含一些自定义对象的Lazy Collection的对象.

通常情况下一切都很好,但是,如果用于序列化的类的命名空间发生了变化,则会出现此问题.

我编写了一个SerializationBinder来指向正确的类,同时反序列化.但由于某种原因,我没有得到反序列化的值.

以下代码片段解释了我遇到的问题;

用于序列化的类:

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>>)); } }}

以上相同的类用于反序列化,但只有名称空间更改为ConsoleApplication14.OtherNamespace

为了使这种反序列化工作,我使用了以下SerializationBinder类:

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,PublicKeyToken=b77a5c561934e089”)) { if (typeName.Equals( “System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass,ConsoleApplication14,PublicKeyToken=null]]”)) return typeof(Collection<ConsoleApplication14.OtherNamespace.MyInnerClass>); if (typeName.Equals( “System.Collections.Generic.List`1[[ConsoleApplication14.MyInnerClass,PublicKeyToken=null]]”)) return typeof(List<ConsoleApplication14.OtherNamespace.MyInnerClass>); if (typeName.Equals( “System.Lazy`1[[System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass,PublicKeyToken=null]],mscorlib,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+@R_41_2419@ed[[System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass,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,PublicKeyToken=b77a5c561934e089]]”)) return typeof(Lazy<Collection<ConsoleApplication14.OtherNamespace.MyInnerClass>>);

请将此代码更改为以下内容

if (typeName.Equals( “System.Lazy`1+@R_41_2419@ed[[System.Collections.ObjectModel.Collection`1[[ConsoleApplication14.MyInnerClass,PublicKeyToken=b77a5c561934e089]]”)){ return Type.GetType(typeName.Replace(“ConsoleApplication14.MyInnerClass”,”ConsoleApplication14.OtherNamespace.MyInnerClass”));}

类型应为@R_41_2419@ed类,在Lazy source code中声明

public class Lazy<T>{ #region Inner classes /// <summary> /// wrapper class to @R_41_2419@ the initialized value,this is mainly created to avoid @R_41_2419@ing/un@R_41_2419@ing the value each time the value is called in case T is /// a value type /// </summary> [Serializable] class @R_41_2419@ed { internal @R_41_2419@ed(T value) { m_value = value; } internal T m_value; }

希望这有帮助.