代码之家  ›  专栏  ›  技术社区  ›  strager

未调用反序列化构造函数

  •  2
  • strager  · 技术社区  · 14 年前

    我正在使用 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter . 我有一个收藏包 List . 当我反序列化集合(它反序列化 列表 列表 如果任何元素实现 ISerializable 除了 我在 列表


    主要

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

    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 是(精简的)集合 列表 . NullPlugin IPlugin 哪些工具 可序列化 ,和 NotNullPlugin 是一个 但事实并非如此。

    1. 只留下代码,反序列化的集合 { null, null } .
    2. 取消注释中的行 插头未收集 原因 要成功反序列化,而 NotNullPlugin公司 { NullPlugin, null } .
    3. collection.Add(new NullPlugin()); 排队 Main NotNullPlugin公司 要成功反序列化。收藏是 { NotNullPlugin } .

    4. 空插件 未成功序列化,从不调用私有反序列化构造函数。

    5. 列表 直接(例如 PluginCollection.plugins 公开和克隆 collection.plugins 在里面 主要 )生成预期结果(即反序列化成功,返回的列表中没有空元素)。

    { NullPlugin, NotNullPlugin } ,我看不出它不应该出现的原因。是什么导致了失败?

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

    1 回复  |  直到 14 年前
        1
  •  3
  •   sisve    14 年前

    我看到的第一件事是假设SerializationInfo.GetValue在反序列化构造函数中调用时将返回已初始化的列表。但事实并非如此,您只收到一个列表的引用,该列表将在所有操作完成后填充。您可以使用 IDeserializationCallback 当整个对象图被反序列化时触发的接口。