我正在使用 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
的(精简)集合。 NullPlugin
是 IPlugin
它实现了 ISerializable
,和NotNullPlugin
是 IPlugin
但事实并非如此。
- 不考虑代码,反序列化后的集合为
{ null, null }
. - 取消注释
PluginCollection
中的行原因NullPlugin
成功反序列化,而NotNullPlugin
仍未反序列化。该集合是{ NullPlugin, null }
. 评论
collection.Add(new NullPlugin());
线路Main
原因NotNullPlugin
才能成功反序列化。该集合是{ NotNullPlugin }
。何时
NullPlugin
未成功序列化,则永远不会调用私有(private)反序列化构造函数。正在序列化
List
直接(例如,通过将PluginCollection.plugins
公开并在collection.plugins
中克隆Main
)产生预期的结果(即反序列化成功并且返回的列表中没有 null 元素)。
我期望当前代码的集合返回 { NullPlugin, NotNullPlugin }
,而且我认为没有理由不这样做。什么可能导致失败?
(此问题发生在直接克隆对象之外,但克隆是显示此错误的最简单方法。)
最佳答案
我看到的第一件事是假设 SerializationInfo.GetValue 在反序列化构造函数中调用时将返回初始化列表。情况并非如此,您仅收到对列表的引用,该列表将在一切完成后填充。您可能想使用IDeserializationCallback当整个对象图被反序列化时触发的接口(interface)。
如果列表包含您的实例,在调用构造函数之前如何完全实例化它?
关于c# - 未调用反序列化 ctor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4136589/