【问题标题】:Not able to deserialize Lazy object无法反序列化惰性对象
【发布时间】:2017-10-24 13:42:37
【问题描述】:

我想序列化和反序列化包含一些自定义对象的LazyCollection 的对象。

通常一切正常,但是,如果用于序列化的类的名称空间发生更改,则会出现此问题。

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

以下代码 sn-p 解释了我遇到的问题;

用于序列化的类:

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, 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();
        }
        //-----------------------------------------------------
    }

当调用反序列化延迟对象的Value 属性时,我得到NullReferenceException。 (即当objOfOtherNamespaceClass.CollectionOfInnerObj.Value 被调用时)

请帮我解决这个问题...

【问题讨论】:

  • 我记得,当循环依赖在(反)序列化图形中时,带有 ISurrogate 的 BinaryFormatter 有一个错误,并且没有打算修复它。我不确定,但这种行为看起来很相似。

标签: c# serialization deserialization lazy-initialization serializationbinder


【解决方案1】:

问题在你已经突出显示的行中

//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 类,在 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;
    }

希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 2016-12-30
    • 2014-11-12
    • 1970-01-01
    • 2014-08-04
    • 2015-05-29
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    相关资源
    最近更新 更多