c# - 未调用反序列化 ctor

标签 c# serialization

我正在使用 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 执行序列化。我有一个包含 List 的集合。当我反序列化集合(反序列化 List )时,所有 List如果任何元素实现 ISerializable,则 的元素为 null ,除了那些我与 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 的(精简)集合。 NullPluginIPlugin它实现了 ISerializable ,和NotNullPluginIPlugin但事实并非如此。

  1. 不考虑代码,反序列化后的集合为 { null, null } .
  2. 取消注释 PluginCollection 中的行原因NullPlugin成功反序列化,而 NotNullPlugin仍未反序列化。该集合是{ NullPlugin, null } .
  3. 评论collection.Add(new NullPlugin());线路 Main原因NotNullPlugin才能成功反序列化。该集合是{ NotNullPlugin }

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

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

我期望当前代码的集合返回 { NullPlugin, NotNullPlugin } ,而且我认为没有理由不这样做。什么可能导致失败?

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

最佳答案

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

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

关于c# - 未调用反序列化 ctor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4136589/

相关文章:

java - Spring 启动 jackson : How to remove nulls from java array?

c# - 任何现有的 Windows DNS 解析器项目? C++ 或 C# 都可以

c# - 从字符串中解析日期时间

C# 表单 - 清除按钮、图片框中的表单,

c# - 构建全双工客户端/服务器软件时应该从哪里开始?

Java 在添加自己的接口(interface)后抛出 NotSerializableException

c# - 是否有用于 .net 的序列化程序将输出 c# 代码?

c# - 如何将元素的背景颜色与 2 个半透明元素背景颜色相匹配

c++ - 序列化 boost 变体;非常奇怪和迟钝的编译器错误(MSVC 2010)

c# - 是否可以将 MongoDB 的 "ISODate"字段反序列化为 JToken (C#)?