【问题标题】:Strange deserialization error, child objects are not fully deserialized奇怪的反序列化错误,子对象没有完全反序列化
【发布时间】:2023-03-08 17:18:01
【问题描述】:

我刚刚注意到二进制序列化中的一个奇怪行为:当我在我的类中反序列化一个字典并尝试立即向其中添加一些内容时,我收到一个错误,因为它没有完全初始化:

[Serializable]
class Foo : ISerializable
{
    public Dictionary<int, string> Dict { get; private set; }

    public Foo()
    {
        Dict = new Dictionary<int, string>();
    }

    public Foo(SerializationInfo info, StreamingContext context)
    {
        Dict = (Dictionary<int, string>)info.GetValue("Dict", typeof(Dictionary<int, string>));
        Dict.Add(99, "test"); // Error here
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Dict", Dict);
    }

}

在我向字典中添加数据的那一行,我得到一个NullReferenceException,但Dict 属性不为空:它已实例化,但未初始化(其所有字段均为0 或空)。我怀疑它只是用FormatterServices.GetUninitializedObject 创建的,但实际上还没有反序列化。

我知道此时,也许它还没有被完全初始化应该。所以我尝试了另一种方法,通过实现IDeserializationCallback 接口。 MSDN 说:

实现当前接口,以支持在对象图的反序列化完成时调用的方法。

如果一个对象需要对其子对象执行代码,它可以延迟 这个动作,实现IDeserializationCallback,并执行代码 只有在这个接口被回调的时候

所以这似乎正是我所需要的,我希望我的字典在调用 OnDeserialization 时被完全初始化......但我得到了同样的错误!

[Serializable]
class Foo : IDeserializationCallback
{
    public Dictionary<int, string> Dict { get; private set; }

    public Foo()
    {
        Dict = new Dictionary<int, string>();
    }

    public void OnDeserialization(object sender)
    {
        Dict.Add(99, "test"); // Error here
    }
}

由于IDeserializationCallback 旨在对子对象执行代码,我希望此时子对象已完全初始化。请注意,如果我在字典上手动调用OnDeserialize,它可以正常工作,但不知何故我认为我不应该这样做......

这种行为正常吗?谁能解释这里发生了什么?

【问题讨论】:

  • 我已经检查过了,事件 [OnDeserialized] 属性没有帮助。此外,我检查了 .NET 源代码,并根据它们初始化所有内容,当调用 [OnDeserialized]IDeserializationCallback.OnDeserialization
  • OnDeserialization 在整个对象图被反序列化时被调用。我怀疑真正的问题出在序列化代码中。从这里看不到。

标签: .net serialization binaryformatter ideserializationcallback


【解决方案1】:

您需要在 OnDeserialization 处理程序中实例化您的 Dictionary

public void OnDeserialization(object sender)
{
    Dict = new Dictionary<int, string>();
    Dict.Add(99, "test"); // Error here
}

【讨论】:

  • 如果我这样做,它不会是我序列化的字典......无论如何,我认为你误解了我的问题:我不是在问如何解决问题,我已经有解决方法它。我的问题是为什么它会这样,因为文档提出了不同的行为。
【解决方案2】:

如果您将Dict.OnDeserialization(sender) 添加到您的反序列化处理程序中,那么一切都会好起来的。

所以,这行得通:

    [Serializable]
    class Foo : IDeserializationCallback
    {
        public Dictionary<int, string> Dict { get; private set; }

        public Foo()
        {
            Dict = new Dictionary<int, string>();
        }

        public void OnDeserialization(object sender)
        {
            // The dictionary is initialized with values in next line
            Dict.OnDeserialization(sender);
            Dict.Add(99, "test");
        }
    }

【讨论】:

  • 从源代码来看,Dictionary 似乎只有在整个对象图通过 OnDeserialization 反序列化后才对其内部进行后处理。这个钩子在对象之间不是确定性地调用的,所以如果你的 Foo 需要调用字典“OnDeserializing”,它必须手动调用字典的方法。根据源代码注释,它可能被多次调用而没有问题。 (第一次之后的调用导致无操作。)注意,出于同样的原因,您应该检查 Foo 的 OnDeserialization 方法以保护多个调用。
猜你喜欢
  • 1970-01-01
  • 2013-02-08
  • 2015-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多