问题 不调用反序列化构造函数


我试图序列化/反序列化包含a的对象 Dictionary<Tuid,Section>。这些都是自定义类型。

在我的代码中我有一种类型 模板 其中包含 Dictionary<Tuid,Section>。它是 模板 我试图序列化/反序列化的类。

要解决此集合是字典的问题,我已经实现了 ISerializable 我的Template类接口....

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

这里的策略是将字典“解包”成两个单独的列表,并将它们单独存储在序列化流中。然后他们会在之后重新创建。

我的 部分 班级也是罪魁祸首 ISerializable...

[Serializable]
public class Section : BaseObject
{

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

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
       // code
    }
}

问题是,当我序列化时 GetObjectData() 在我的模板上调用  我的部分让我相信数据是Serializable并且它被序列化了。

当我反序列化时, 只要 调用Template上的反序列化构造函数。从不调用Section的反序列化构造函数。结果就是打电话给 info.GetValue("Section_Values"....)   返回一个List,但它有一个项目,该项目为null。

为什么我的构造函数反序列化一个段永远不会被调用?可能是该部分内的一些数据不可序列化?如果是这样,如何找出它究竟无法序列化的内容?

更新:我刚刚发现的一件事是用标记的BaseObject for section [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

为什么会发生这种情况?


8568
2017-12-01 10:49


起源

我喜欢你序列化词典的方法:) - Stanislav Stoyanov
我不知道它是否是一个好的方法:)它现在不起作用所以不能那么好:) - Remotec


答案:


其中一个选择是实施

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

在里面Template class,因为默认的serrializer不会调用子对象的构造函数 - Section


11
2017-12-01 11:06



好的,看起来是个好主意 - 如何将我的子对象提取到我的Template类中?另外,奇怪的是反序列化如何知道列表中有1个对象但是它为null。 - Remotec
我不太确定,但我认为你可以重用你的构造函数中的代码 Template 和 Section - oleksii
一世 认为 这更倾向于在您不想序列化的类中设置值。例如。如果您有一个计算值,您可以从其他两个值中计算出来。你可以用这种方法计算它。 - Remotec


我相信你的问题是因为序列化的工作方式(我似乎首先回想起它的宽度,而不是深度优先)。这意味着它会对您的模板进行反序列化,然后在其中创建空间以添加到您的部分中。

但是这些部分尚未反序列化,在模板完成反序列化后,它们将被反序列化。您应该能够通过使用断点来检查这一点,并让您的代码继续运行。解决这个问题的方法是使用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]);
        } 
    }
}

2
2017-12-01 11:26