序列化 HashSet

发布于 2024-10-03 02:13:44 字数 1360 浏览 3 评论 0原文

我正在尝试序列化哈希集,但我没有运气。每当我尝试打开序列化数据时,我都会得到一个空的 HashSet。然而,列表工作得很好。示例代码:

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

运行时,它会打印出:

Printing Hashset:
Printing List:
One
Two
Three

所以 List 工作正常,但 HashSet 返回为空。有点卡住了——有人能看出我做错了什么吗?谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独木成林 2024-10-10 02:13:44

更新

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

var hashset = (HashSet<string>)info.GetValue("hashset", typeof(HashSet<string>));
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<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[]));
  }
}

并且 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< /a> (它可以处理此类类型)或使用序列化助手,例如 protobuf.net、json.net 等。请参阅 为什么二进制序列化比 xml 序列化更快?WCF 绑定使用的序列化的性能测试

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

巷子口的你 2024-10-10 02:13:44

不同之处在于 HashSet<>实现 ISerialized、List<>没有。解决方法是显式调用其 OnDeserialization() 方法,尽管我不确定这是否是正确的做法。

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

The difference is that HashSet<> implements ISerializable, List<> doesn't. The workaround is to call its OnDeserialization() method explicitly, albeit that I'm not sure whether that's the right thing to do.

        var hashset = (HashSet<string>)info.GetValue("hashset", typeof(HashSet<string>));
        hashset.OnDeserialization(this);
        var list = (List<string>)info.GetValue("list", typeof(List<string>));
        // etc..
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文