序列化HashSet

我正在尝试序列化Hashset,但我没有运气。 每当我尝试打开序列化数据时,我都会得到一个空的HashSet。 但是,List工作正常。 示例代码:

[Serializable()] public class MyClass : ISerializable { public MyClass(SerializationInfo info, StreamingContext ctxt) { HashSet hashset = (HashSet)info.GetValue("hashset", typeof(HashSet)); List list = (List)info.GetValue("list", typeof(List)); Console.WriteLine("Printing Hashset:"); foreach (string line in hashset) { Console.WriteLine(line); } Console.WriteLine("Printing List:"); foreach (string line in list) { Console.WriteLine(line); } } public void GetObjectData(SerializationInfo info, StreamingContext ctxt) { HashSet hashset = new HashSet(); hashset.Add("One"); hashset.Add("Two"); hashset.Add("Three"); info.AddValue("hashset", hashset); List list = new List(); list.Add("One"); list.Add("Two"); list.Add("Three"); info.AddValue("list", list); } } 

并且在运行时打印出来:

 Printing Hashset: Printing List: One Two Three 

所以List工作正常,但HashSet回来了。 有点卡住 – 谁能看到我做错了什么? 谢谢

更新

正如Hans Passant 所说 ,有简单的解决方法,只需手动调用HashSet.OnDeserialization 。

 var hashset = (HashSet)info.GetValue("hashset", typeof(HashSet)); hashset.OnDeserialization(this); 

它还有助于其他通用集合。


据我所知,这可能是HashSet实现中的错误。 HashSet正确序列化为SerializationInfo

 public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) { throw new ArgumentNullException("info"); } info.AddValue("Version", this.m_version); info.AddValue("Comparer", this.m_comparer, typeof(IEqualityComparer)); info.AddValue("Capacity", (this.m_buckets == null) ? 0 : this.m_buckets.Length); if (this.m_buckets != null) { T[] array = new T[this.m_count]; this.CopyTo(array); info.AddValue("Elements", array, typeof(T[])); } } 

SerializationInfo正确还原。 您也可以自己检查,看看: (((System.Collections.Generic.HashSet)(info.m_data[0]))).m_siInfo.m_data[3]但无法恢复其状态:

它所做的只是存储SerializationInfo

 protected HashSet(SerializationInfo info, StreamingContext context) { this.m_siInfo = info; } 

您可以检查(hashset).m_siInfo.MemberValues[3] ,值由格式化程序正确恢复,但不是由HashSet “解释”。

类似的问题有Dictionary或者例如LinkedList

List (或类似的基于数组的集合,例如Stack )没有问题,因为它们被序列化为数组(没有特殊逻辑)。

解决方法由Hans Passant发布。

恕我直言, BinaryFormatter并不是真正优质和有效的存储价值方式。 你可以尝试使用DataContractSerializer (它可以处理这些类型)或者使用序列化帮助程序,如protobuf.net,json.net等。请参阅为什么二进制序列化比xml序列化更快? 和WCF绑定使用的序列化的性能测试

区别在于HashSet <>实现ISerializable,List <>不实现。 解决方法是显式调用它的OnDeserialization()方法,虽然我不确定这是否正确。

  var hashset = (HashSet)info.GetValue("hashset", typeof(HashSet)); hashset.OnDeserialization(this); var list = (List)info.GetValue("list", typeof(List)); // etc..