Сериализация HashSet - PullRequest
       27

Сериализация HashSet

2 голосов
/ 16 ноября 2010

Я пытаюсь сериализовать Hashset, но мне не повезло. Всякий раз, когда я пытаюсь открыть сериализованные данные, я получаю пустой 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

Итак, список работает нормально, но HashSet возвращается пустым. Немного застрял - кто-нибудь может увидеть, что я делаю не так? Спасибо

Ответы [ 2 ]

3 голосов
/ 16 ноября 2010

Обновление

Как Ганс Пассант заявил есть простой обходной путь, просто вызовите HashSet.OnDeserialization вручную.

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

Это также помогает с другими универсальными коллекциями.


Насколько я понимаю, это, вероятно, ошибка в реализации HashSet<T>. 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<string>)(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<TKey,TValue> или, например, LinkedList<T>.

List<T> (или аналогичные коллекции на основе массива, такие как Stack<T>) не имеют проблем, поскольку они сериализованы как массив (без специальной логики).

Обходной путь был опубликован Хансом Пассантом.

ИМХО, BinaryFormatter не очень хороший и эффективный способ хранения значений. Вы можете попробовать использовать DataContractSerializer (он может обрабатывать такие типы) или использовать помощники по сериализации, такие как protobuf.net, json.net и т. Д. См. Почему двоичная сериализация быстрее, чем сериализация xml? и Тесты производительности сериализаций, используемые привязками WCF

2 голосов
/ 16 ноября 2010

Разница в том, что HashSet <> реализует ISerializable, а 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..
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...