序列化一个 HashSet [英] Serializing a HashSet
问题描述
我正在尝试序列化一个哈希集,但我没有运气.每当我尝试打开序列化数据时,都会得到一个空的 HashSet.但是,列表工作正常.示例代码:
[Serializable()]公共类 MyClass : ISerializable{公共 MyClass(SerializationInfo 信息,StreamingContext ctxt){哈希集<字符串>hashset = (HashSet)info.GetValue("hashset", typeof(HashSet));列表<字符串>list = (List)info.GetValue("list", typeof(List));Console.WriteLine("打印哈希集:");foreach(哈希集中的字符串行){Console.WriteLine(line);}Console.WriteLine("打印列表:");foreach(列表中的字符串行){Console.WriteLine(line);}}public void GetObjectData(SerializationInfo info, StreamingContext ctxt){哈希集<字符串>hashset = new HashSet();hashset.Add("一");hashset.Add("两个");hashset.Add("三");info.AddValue("hashset", hashset);列表<字符串>list = new List();list.Add("一");list.Add("两个");list.Add("三个");info.AddValue("list", list);}}
当运行时,它打印出来:
打印哈希集:印刷清单:一二三
所以 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){如果(信息==空){throw new ArgumentNullException("info");}info.AddValue("版本", this.m_version);info.AddValue("Comparer", this.m_comparer, typeof(IEqualityComparer));info.AddValue("Capacity", (this.m_buckets == null) ? 0 : this.m_buckets.Length);如果(this.m_buckets != null){T[] 数组 = 新 T[this.m_count];this.CopyTo(array);info.AddValue("元素", 数组, typeof(T[]));}}
和 SerializationInfo
正确恢复.也可以自己查,看看:(((System.Collections.Generic.HashSet
但未能恢复其状态:
它所做的只是简单地存储SerializationInfo
:
protected HashSet(SerializationInfo info, StreamingContext context){this.m_siInfo = 信息;}
您可以检查(hashset).m_siInfo.MemberValues[3]
,值被格式化程序正确恢复,但没有被HashSet
解释".
类似的问题有 Dictionary
或例如LinkedList
.
List
(或类似的基于数组的集合,例如 Stack
)没有问题,因为它们序列化为数组(没有特殊逻辑).><块引用>
Hans Passant 发布了解决方法.
恕我直言,BinaryFormatter
并不是真正好的和有效的存储值的方式.您可以尝试使用 DataContractSerializer(它可以处理此类类型)或使用序列化助手,例如 protobuf.net、json.net 等.请参阅 为什么二进制序列化比 xml 序列化快? 和 WCF 绑定使用的序列化的性能测试
I'm trying to serialize a Hashset but I'm having no luck. Whenever I try to open the serialized data, I get an empty HashSet. However, a List works fine. Example code:
[Serializable()]
public class MyClass : ISerializable
{
public MyClass(SerializationInfo info, StreamingContext ctxt)
{
HashSet<string> hashset = (HashSet<string>)info.GetValue("hashset", typeof(HashSet<string>));
List<string> list = (List<string>)info.GetValue("list", typeof(List<string>));
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<string> hashset = new HashSet<string>();
hashset.Add("One");
hashset.Add("Two");
hashset.Add("Three");
info.AddValue("hashset", hashset);
List<string> list = new List<string>();
list.Add("One");
list.Add("Two");
list.Add("Three");
info.AddValue("list", list);
}
}
And when run, it prints out:
Printing Hashset:
Printing List:
One
Two
Three
So the List works fine, but the HashSet comes back empty. A little stuck - can anyone see what I'm doing wrong? Thanks
Update:
As Hans Passant stated there are simple workaround, just call HashSet.OnDeserialization manually.
var hashset = (HashSet<string>)info.GetValue("hashset", typeof(HashSet<string>));
hashset.OnDeserialization(this);
It also helps with other Generic collections.
As far as I can see this is probably bug in HashSet<T>
implementation. HashSet
correctly serialized into 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<T>));
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[]));
}
}
and SerializationInfo
correctly restored. You can check also by yourself, take a look to: (((System.Collections.Generic.HashSet<string>)(info.m_data[0]))).m_siInfo.m_data[3]
but fails to restore its state:
All it do is simply stores SerializationInfo
:
protected HashSet(SerializationInfo info, StreamingContext context)
{
this.m_siInfo = info;
}
You can check (hashset).m_siInfo.MemberValues[3]
, values was correcly restored by formatter but not "interpreted" by HashSet
.
Similar problem has Dictionary<TKey,TValue>
or e.g. LinkedList<T>
.
List<T>
(or similar array based collections such as Stack<T>
) has no problem since they serialized as array (without special logic).
Workaround was posted by Hans Passant.
IMHO, BinaryFormatter
is not really good and efficient way to store values. You can try to use DataContractSerializer (it can handle such types) or go with serialization helpers such as protobuf.net, json.net etc. See Why is binary serialization faster than xml serialization? and Performance Tests of Serializations used by WCF Bindings
这篇关于序列化一个 HashSet的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!