La sérialisation d'un HashSet
Je suis en train de sérialiser un Hashset, mais je vais avoir pas de chance. Chaque fois que j'essaie d'ouvrir les données sérialisées, je reçois un vide HashSet. Cependant, une Liste fonctionne très bien. Exemple de 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);
}
}
Et lorsqu'il est exécuté, il imprime:
Printing Hashset:
Printing List:
One
Two
Three
De sorte que la Liste fonctionne bien, mais le HashSet est de retour à vide. Un peu coincé - n'importe qui peut voir ce que je fais mal? Grâce
- Pourquoi faites-vous la sérialisation vous-même? Pourquoi ne pas utiliser le DataContractSerializer ?
Vous devez vous connecter pour publier un commentaire.
Mise à jour:
Comme Hans Passant a déclaré il y a solution de contournement simple, il suffit d'appeler HashSet.OnDeserialization manuellement.
Il aide également avec d'autres Génériques collections.
Aussi loin que je peux voir, c'est probablement un bug dans
HashSet<T>
mise en œuvre.HashSet
correctement sérialisé dansSerializationInfo
:et
SerializationInfo
correctement restaurée. Vous pouvez vérifier par vous-même, jetez un oeil à:(((System.Collections.Generic.HashSet<string>)(info.m_data[0]))).m_siInfo.m_data[3]
mais ne parvient pas à restaurer son état:Tous, il n'est tout simplement magasins
SerializationInfo
:Vous pouvez vérifier
(hashset).m_siInfo.MemberValues[3]
, les valeurs ont été correcly restauré par le formateur, mais pas "interprété" parHashSet
.Problème similaire a
Dictionary<TKey,TValue>
ou, par exemple,LinkedList<T>
.List<T>
(ou similaire réseau sur la base des collectionsStack<T>
) n'a pas de problème puisqu'ils sérialisé sous forme de tableau (sans logique).À mon humble avis,
BinaryFormatter
n'est pas vraiment bon et efficace pour stocker des valeurs. Vous pouvez essayer d'utiliser DataContractSerializer (il peut gérer de tels types) ou aller avec la sérialisation aides telles que protobuf.net, json.net etc. Voir Pourquoi est-sérialisation binaire plus vite que la sérialisation xml? et Les Tests de performances de Serializations utilisé par la WCF Liaisonsint
champ, vous allez vous retrouver avec ~153 octets du fichier, car il contient tous les noms de type de. Comparer avec les 4 octets de la valeur deint
lui-même. 2. VérifierBinaryFormatter
mise en œuvre ou simplement de mesurer la performance à comparer avec la plaine de la valeur binaire de l'écrivain. 3. N'oubliez pas de problèmes de compatibilité, de sorte que si vous mettez à jour l'assemblée sur le serveur, vous devez utiliser quelques astuces pour ne pas échouer avec la désérialisation des anciennes valeurs.BinaryFormatter
que notre sérialisation backend, mais il trouve assez de ne pas optimale pendant certain nombre de tests. Notre système distribué est de 10 à 50 000 nœuds, nous avons terminé avec notre propre réalisation, en 2007, mais la réflexion sur le passage à ProtoBuffers depuis que notre solution est assez semblable.fwrite
est plus rapide et plus petit, vous n'avez pas de sécurité de type (et tout un tas d'autres subtilités, comme cyclique de données, etc). Si la taille est un problème, vous pouvez simplement gzip le flux d'octets.BinaryFormatter
ajoute énormément de métadonnées avec les descriptions de champ (y compris la sauvegarde du compilateur noms de champ), types, etc. Même gzip ne peux pas beaucoup vous aider. Aussi, en raison de lourdes réflexion dépendance il vraiment lent.BinaryFormatter
est juste pratique façon pour sérialiser/désérialiser les données à transférer. Votre propre mise en œuvre peut être autant en sécurité que vous avez besoin/envie. Après tout, il vient d'octets et de le rendresafe
convention est atteint par l'utilisation de certains autres wrappers soit cadre ou de votre propre. Voir aussi Marc réponses qu'il donne quelques infos. J'ai mis à jour ma réponse avec des liens vers eux.FormatterTypeStyle
,FormatterAssemblyStyle
etTypeFilterLevel
.System.IO.BinaryWriter
nous venons de mettre en œuvre leurs propres sérialiseur pour les types de base (int, float, paniers int, des tableaux, des jeux, des cartes, etc.) et a généré sérialiseurs semblable, WCF attributs (DataContract
,DataMember
). De sorte que chaque objet peut être sérialisé par nos sérialisation backend (juste des données), soit par courrier en écrivant propre logique de sérialisation, à l'aide de types de base ou d'objets connus. La dernière variante permet par exemple de construire et de sérialiser les données des deltas ou des types complexes qui peuvent efficacement "emballé" manuellement.k
au lieu de 153 octets. Mais les performances n'ont pas disparu.La différence est que HashSet<> met en œuvre ISerializable, List<> ne fonctionne pas. La solution de contournement est d'appeler son OnDeserialization() la méthode explicite, bien que je ne suis pas sûr de savoir si c'est la bonne chose à faire.
HashSet<T>
ont à mettre en œuvreISerializable.OnDeserialization()
et de ne pas vérifier.