反序列化构造函数未被调用

12

我正在尝试对包含 Dictionary<Tuid,Section> 的对象进行序列化/反序列化。这两者都是自定义类型。

在我的代码中,我有一个名为模板(Template)的类型,它包含Dictionary<Tuid,Section>。 我正试图对 模板 类进行序列化/反序列化。

为了解决此集合是字典的问题,我在我的 Template 类上实现了 ISerializable 接口....

[Serializable]
public class Template : ISerializable
{
    protected Template(SerializationInfo info, StreamingContext context)
    {
        // Deserialize the sections
        List<Tuid> tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        List<Section> sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();

        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        }           
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        List<Tuid> tuids = new List<Tuid>();
        List<Section> sections = new List<Section>();

        foreach (KeyValuePair<Tuid, Section> kvp in _sections)
        {
            tuids.Add(kvp.Key);
            sections.Add(kvp.Value);
        }

        info.AddValue("Sections_Keys", tuids, typeof(List<Tuid>));
        info.AddValue("Sections_Values", sections, typeof(List<Section>));
   }

这里的策略是将字典“展开”为两个单独的列表,并将它们分别存储在序列化流中。然后在之后重新创建它们。

我的Section类还实现了ISerializable...

[Serializable]
public class Section : BaseObject
{

    protected Section(SerializationInfo info, StreamingContext context):base(.....)
    {
        // Code
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
       // code
    }
}
问题在于当我序列化时,我的模板和部分都会调用GetObjectData(),这使我相信数据是可序列化的,并且正在进行序列化。
当我反序列化时,只有模板的反序列化构造函数被调用。部分的反序列化构造函数从未被调用。这导致对info.GetValue("Section_Values"....)的调用返回一个List,但其中只有一个null项。
为什么我的反序列化部分的构造函数从未被调用?它可能是由于部分内部的某些数据不能序列化吗?如果是这样,如何找出确切不能序列化的内容?
更新:我刚刚发现的一件事是,部分的BaseObject标有[Serializable],但不实现ISerializable
另外,我想知道反序列化代码要求有多严格-它是否会针对同时构造基类的构造函数?
更新:好的,我已经追踪到问题的根源在于部分的序列化。代码看起来像这样...
protected Section(SerializationInfo info, StreamingContext context):base(.....)
{
    // Code
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{

    //info.AddValue("CustomObject", ClientInfo, typeof(CustomObject));
    //info.AddValue("Description", Description, typeof(string));
}

将两行代码均注释掉后,没有任何序列化操作,Section 类的反序列化构造函数被调用。如果我添加字符串值,则仍然正常。但是,是的 - 你猜对了 - 如果我将 CustomObject 添加到序列化流中,则不会调用反序列化构造函数。

请注意...

  • Section 的反序列化构造函数是一个空方法 - 我不尝试对反序列化数据进行任何操作。
  • Section 的基本构造函数已被打桩以传递新的有效对象,并且我已确认这可以正常运行。
  • 没有抛出任何异常告诉我无法序列化 CustomObject
  • CustomObject 是可序列化的,其 GetObjectData() 方法可以正常运行,并且在反序列化时它也被正确构造。

纯粹通过将此可序列化对象添加到流中,框架就无法将其反序列化到 Section 的反序列化构造函数中,这似乎很奇怪!!

为什么会发生这种情况呢?


我喜欢你序列化字典的方法 :) - Aineislis Cole
1
我不知道这是否是一个好的方法 :) 好吧,它现在不起作用,所以肯定不是很好 :) - Remotec
你是如何成功调用GetObjectData方法的?我已经尝试了一段时间,但这个方法从来没有被调用过。 - GuidoG
2个回答

13

其中一个选项是实现

[OnDeserializing]
void OnDeserializing(StreamingContext c)
{
    //create what is required here
}

Template类中,由于默认的序列化程序不调用子对象的构造函数 - Section


1
好的,看起来是个不错的想法 - 如何将我的子对象提取到我的模板类中?此外,反序列化如何知道列表中有1个对象但它为空,这很奇怪。 - Remotec
我不是很确定,但我认为您可以重用TemplateSection的构造函数中的代码。 - oleksii
2
我认为这更适用于在类中设置不想序列化的值。例如,如果您有一个可以从其他两个值计算出来的计算值,您可以在此方法中进行计算。 - Remotec

2
我认为你的问题是由于序列化工作方式引起的(我记得它是按宽度优先,而不是深度优先)。这意味着它会反序列化您的模板,然后在其中创建空间以添加您的部分。
然而,这些部分尚未反序列化,它们将在模板完成反序列化后进行反序列化。您可以使用断点来检查此内容并让您的代码运行一段时间。解决此问题的方法是使用oleksii的解决方案或类似地使用IDeserializationCallback。
当实例完成反序列化(及其成员)时,IDeserializationCallback会调用一个方法,允许您进行一些连接。我建议您尝试以下更改:
[Serializable]
public class Template : ISerializable, IDeserializationCallback
{
    private List<Tuid> tuids;
    private List<Section> sections
    protected Template(SerializationInfo info, StreamingContext context)
    {
        tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();
    }

    public void OnDeserialization(object sender)
    {
        // Section serialization constructor should have been called by this point
        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        } 
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接