【问题标题】:Deserialization constructor not called未调用反序列化构造函数
【发布时间】:2011-12-01 10:49:51
【问题描述】:

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

在我的代码中,我有一种 模板,其中包含 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() 时,我的模板我的部分都被调用,这让我相信数据是可序列化的并且它正在被序列化。

当我反序列化时,只有 Template 上的反序列化构造函数被调用。 Section 的反序列化构造函数永远不会被调用。这样做的结果是对info.GetValue("Section_Values"....) 的调用确实返回了一个List,但其中有一个项目并且该项目为空。

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

更新:我刚刚发现的一件事是,部分的 BaseObject 标记为 [Serializable],但没有实现 ISerializable

此外,我想知道 Deserialize 代码有多么繁琐——它是否会针对同时构造基类的构造函数?

更新..

好的,我已经将问题追溯到该部分的序列化。代码看起来像这样......

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的反序列化器构造函数!!

为什么会发生这种情况?

【问题讨论】:

  • 我喜欢你序列化字典的方法:)
  • 我不知道这是否是一个好方法 :) 好吧,它目前不起作用,所以不可能那么好 :)
  • 你是如何设法让 GetObjectData 被调用的?我尝试了一段时间,但这个方法永远不会被调用

标签: c# .net serialization iserializable


【解决方案1】:

其中一个选项是实施

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

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

【讨论】:

  • 好的,看起来是个好主意——如何将我的子对象提取到我的模板类中?此外,奇怪的是反序列化如何知道列表中有 1 个对象但它为空。
  • 我不太确定,但我认为您可以重用 TemplateSection 的构造函数中的代码
  • 认为这更多是为了在你不想序列化的类中设置值。例如。如果你有一个计算值,你可以从其他两个值中计算出来。你可以用这种方法计算。
【解决方案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]);
        } 
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2020-10-20
    • 2011-12-29
    • 1970-01-01
    • 2016-07-13
    • 1970-01-01
    • 2011-07-09
    相关资源
    最近更新 更多