【问题标题】:Deserialization ctor not called未调用反序列化ctor
【发布时间】:2010-11-09 17:27:24
【问题描述】:

我正在使用System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 执行序列化。我有一个包含List 的集合。当我反序列化集合(反序列化List)时,如果任何元素实现ISerializable,则所有List 的元素都为空,除了那些与我一起序列化的项目List。这是一个测试用例:


主要

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

static class Program {
    static void Main(string[] args) {
        var collection = new PluginCollection();
        collection.Add(new NullPlugin());
        collection.Add(new NotNullPlugin());

        Clone(collection);
    }

    private static byte[] Serialize(object obj, IFormatter formatter) {
        using (var writer = new MemoryStream()) {
            formatter.Serialize(writer, obj);

            return writer.GetBuffer().Take((int) writer.Length).ToArray();
        }
    }

    private static object Deserialize(byte[] data, IFormatter formatter) {
        using (var stream = new MemoryStream(data)) {
            return formatter.Deserialize(stream);
        }
    }

    public static T Clone<T>(T obj) {
        var cloner = new BinaryFormatter {
            Context = new StreamingContext(StreamingContextStates.Clone)
        };

        return (T) Deserialize(Serialize(obj, cloner), cloner);
    }
}

IPlugin 和实现者

interface IPlugin {
}

[Serializable]
sealed class NullPlugin : IPlugin, ISerializable {
    public NullPlugin() {
    }

    private NullPlugin(SerializationInfo info, StreamingContext context) {
    }

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

[Serializable]
sealed class NotNullPlugin : IPlugin {
}

插件集合

[Serializable]
sealed class PluginCollection : ISerializable {
    private readonly IList<IPlugin> plugins = new List<IPlugin>();

    public PluginCollection() {
    }

    private PluginCollection(SerializationInfo info, StreamingContext context) {
        var plugins = (IEnumerable<IPlugin>) info.GetValue("Plugins", typeof(IEnumerable<IPlugin>));
        //var plugin = (IPlugin) info.GetValue("Plugin", typeof(IPlugin));

        System.Diagnostics.Debug.Assert(!plugins.Any((p) => p == null));

        AddRange(plugins);
        //Add(plugin);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context) {
        info.AddValue("Plugins", this.plugins);
        //info.AddValue("Plugin", this.plugins.First());
    }

    public void Add(IPlugin plugin) {
        if (plugin == null) {
            throw new ArgumentNullException("plugin");
        }

        this.plugins.Add(plugin);
    }

    private void AddRange(IEnumerable<IPlugin> plugins) {
        if (plugins == null) {
            throw new ArgumentNullException("plugins");
        }

        foreach (var plugin in plugins) {
            Add(plugin);
        }
    }
}

PluginCollection 是带有List 的(精简的)集合。 NullPlugin 是实现 ISerializableIPlugin,而 NotNullPlugin 是未实现的 IPlugin

  1. 不管代码,反序列化的集合是{ null, null }
  2. 取消注释PluginCollection 中的行会导致NullPlugin 成功反序列化,而NotNullPlugin 仍未反序列化。收藏是{ NullPlugin, null }
  3. Main 中注释collection.Add(new NullPlugin()); 行会导致NotNullPlugin 成功反序列化。集合是{ NotNullPlugin }

  4. NullPlugin 未成功序列化时,永远不会调用私有反序列化构造函数。

  5. 直接序列化List(例如,将PluginCollection.plugins 公开并在Main 中克隆collection.plugins)会产生预期的结果(即反序列化成功并且返回列表中没有空元素) .

我希望当前代码的集合返回{ NullPlugin, NotNullPlugin },我看不出有什么理由不这样做。什么可能导致失败?

(此问题在直接克隆对象之外发生,但克隆是显示此错误的最简单方法。)

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    我看到的第一件事是假设 SerializationInfo.GetValue 在反序列化构造函数中调用时将返回初始化列表。情况并非如此,您只会收到对列表的引用,该列表将在一切完成后填充。您可能想要使用IDeserializationCallback 接口,该接口在整个对象图被反序列化时触发。

    如果列表包含您的实例,如何在调用您的构造函数之前将其完全实例化?

    【讨论】:

    • 就是这样!我从来没有想到这一点。以后在处理序列化时,我一定会牢记这一点。
    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 2017-02-11
    • 1970-01-01
    • 2022-01-02
    • 2017-07-16
    • 1970-01-01
    相关资源
    最近更新 更多