序列化一个 HashSet [英] Serializing a HashSet

查看:22
本文介绍了序列化一个 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)(info.m_data[0]))).m_siInfo.m_data[3]但未能恢复其状态:

它所做的只是简单地存储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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆