En développant mon problème précédent , j’ai décidé de (dés) sérialiser ma classe de fichiers de configuration qui fonctionnait très bien.
Je veux maintenant stocker un tableau associatif de lettres de lecteur à mapper (la clé correspond à la lettre du lecteur, la valeur correspond au chemin réseau) et j’ai essayé d’utiliser Dictionary
, HybridDictionary
et Hashtable
mais j’obtiens toujours l’erreur suivante ConfigFile.Load()
ou ConfigFile.Save()
:
Il y avait une erreur reflétant le type “App.ConfigFile”. [snip] System.NotSupportedException: impossible de sérialiser le membre App.Configfile.mappedDrives [snip]
De ce que j’ai lu, Dictionnaires et HashTables peuvent être sérialisés, alors qu’est-ce que je fais mal?
[XmlRoot(ElementName="Config")] public class ConfigFile { public Ssortingng guiPath { get; set; } public ssortingng configPath { get; set; } public Dictionary mappedDrives = new Dictionary(); public Boolean Save(Ssortingng filename) { using(var filestream = File.Open(filename, FileMode.OpenOrCreate,FileAccess.ReadWrite)) { try { var serializer = new XmlSerializer(typeof(ConfigFile)); serializer.Serialize(filestream, this); return true; } catch(Exception e) { MessageBox.Show(e.Message); return false; } } } public void addDrive(ssortingng drvLetter, ssortingng path) { this.mappedDrives.Add(drvLetter, path); } public static ConfigFile Load(ssortingng filename) { using (var filestream = File.Open(filename, FileMode.Open, FileAccess.Read)) { try { var serializer = new XmlSerializer(typeof(ConfigFile)); return (ConfigFile)serializer.Deserialize(filestream); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.ToSsortingng()); return new ConfigFile(); } } } }
Vous ne pouvez pas sérialiser une classe qui implémente IDictionary. Consultez ce lien .
Q: Pourquoi ne puis-je pas sérialiser les hashtables?
A: XmlSerializer ne peut pas traiter les classes implémentant l’interface IDictionary. Cela était dû en partie à des contraintes de planification et en partie au fait qu’une table de hachage n’a pas de contrepartie dans le système de type XSD. La seule solution consiste à implémenter une table de hachage personnalisée qui n’implémente pas l’interface IDictionary.
Donc, je pense que vous devez créer votre propre version du dictionnaire pour cela. Vérifiez cette autre question .
Il y a une solution au blog de Paul Welter – XML Serializable Generic Dictionary
Pour une raison quelconque, le dictionnaire générique dans .net 2.0 n’est pas XML sérialisable. L’extrait de code suivant est un dictionnaire générique sérialisable xml. Le dictionnaire est sérialisable en implémentant l’interface IXmlSerializable.
using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; [XmlRoot("dictionary")] public class SerializableDictionary : Dictionary, IXmlSerializable { public SerializableDictionary() { } public SerializableDictionary(IDictionary dictionary) : base(dictionary) { } public SerializableDictionary(IDictionary dictionary, IEqualityComparer comparer) : base(dictionary, comparer) { } public SerializableDictionary(IEqualityComparer comparer) : base(comparer) { } public SerializableDictionary(int capacity) : base(capacity) { } public SerializableDictionary(int capacity, IEqualityComparer comparer) : base(capacity, comparer) { } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(System.Xml.XmlReader reader) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); bool wasEmpty = reader.IsEmptyElement; reader.Read(); if (wasEmpty) return; while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { reader.ReadStartElement("item"); reader.ReadStartElement("key"); TKey key = (TKey)keySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement("value"); TValue value = (TValue)valueSerializer.Deserialize(reader); reader.ReadEndElement(); this.Add(key, value); reader.ReadEndElement(); reader.MoveToContent(); } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); foreach (TKey key in this.Keys) { writer.WriteStartElement("item"); writer.WriteStartElement("key"); keySerializer.Serialize(writer, key); writer.WriteEndElement(); writer.WriteStartElement("value"); TValue value = this[key]; valueSerializer.Serialize(writer, value); writer.WriteEndElement(); writer.WriteEndElement(); } } #endregion }
Au lieu d’utiliser XmlSerializer
vous pouvez utiliser un System.Runtime.Serialization.DataContractSerializer
. Cela peut sérialiser des dictionnaires et des interfaces sans sueur.
Voici un lien vers un exemple complet, http://theburningmonk.com/2010/05/net-tips-xml-serialize-or-deserialize-dictionary-in-csharp/
Créez un substitut de sérialisation.
Exemple, vous avez une classe avec une propriété publique de type Dictionnaire.
Pour prendre en charge la sérialisation Xml de ce type, créez une classe de valeur-clé générique:
public class SerializeableKeyValue { public T1 Key { get; set; } public T2 Value { get; set; } }
Ajoutez un atsortingbut XmlIgnore à votre propriété d’origine:
[XmlIgnore] public Dictionary SearchCategories { get; set; }
Exposez une propriété publique de type tableau, contenant un tableau d’instances SerializableKeyValue, utilisées pour sérialiser et désérialiser dans la propriété SearchCategories:
public SerializeableKeyValue[] SearchCategoriesSerializable { get { var list = new List>(); if (SearchCategories != null) { list.AddRange(SearchCategories.Keys.Select(key => new SerializeableKeyValue() {Key = key, Value = SearchCategories[key]})); } return list.ToArray(); } set { SearchCategories = new Dictionary(); foreach (var item in value) { SearchCategories.Add( item.Key, item.Value ); } } }
Vous devriez explorer Json.Net, assez facile à utiliser et permettant aux objects Json d’être désérialisés directement dans Dictionary.
james_newtonking
Exemple:
ssortingng json = @"{""key1"":""value1"",""key2"":""value2""}"; Dictionary values = JsonConvert.DeserializeObject>(json); Console.WriteLine(values.Count); // 2 Console.WriteLine(values["key1"]); // value1
Les dictionnaires et les tables de hachage ne sont pas sérialisables avec XmlSerializer
. Par conséquent, vous ne pouvez pas les utiliser directement. Une solution consiste à utiliser l’atsortingbut XmlIgnore
pour masquer ces propriétés du sérialiseur et les exposer via une liste de paires clé-valeur sérialisables.
PS: construire un XmlSerializer
est très coûteux, donc mettez-le toujours en cache s’il y a une chance de pouvoir le réutiliser.
Je voulais une classe SerializableDictionary qui utilisait des atsortingbuts xml pour la clé / valeur, donc j’ai adapté la classe de Paul Welter.
Cela produit xml comme:
"
Code:
using System.Collections.Generic; using System.Xml; using System.Xml.Linq; using System.Xml.Serialization; namespace DataTypes { [XmlRoot("Dictionary")] public class SerializableDictionary : Dictionary, IXmlSerializable { #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; } public void ReadXml(XmlReader reader) { XDocument doc = null; using (XmlReader subtreeReader = reader.ReadSubtree()) { doc = XDocument.Load(subtreeReader); } XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair)); foreach (XElement item in doc.Descendants(XName.Get("Item"))) { using(XmlReader itemReader = item.CreateReader()) { var kvp = serializer.Deserialize(itemReader) as SerializableKeyValuePair; this.Add(kvp.Key, kvp.Value); } } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer serializer = new XmlSerializer(typeof(SerializableKeyValuePair)); XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); ns.Add("", ""); foreach (TKey key in this.Keys) { TValue value = this[key]; var kvp = new SerializableKeyValuePair(key, value); serializer.Serialize(writer, kvp, ns); } } #endregion [XmlRoot("Item")] public class SerializableKeyValuePair { [XmlAtsortingbute("Key")] public TKey Key; [XmlAtsortingbute("Value")] public TValue Value; /// /// Default constructor /// public SerializableKeyValuePair() { } public SerializableKeyValuePair (TKey key, TValue value) { Key = key; Value = value; } } } }
Tests unitaires:
using System.IO; using System.Linq; using System.Xml; using System.Xml.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DataTypes { [TestClass] public class SerializableDictionaryTests { [TestMethod] public void TestSsortingngSsortingngDict() { var dict = new SerializableDictionary(); dict.Add("Grass", "Green"); dict.Add("Snow", "White"); dict.Add("Sky", "Blue"); dict.Add("Tomato", "Red"); dict.Add("Coal", "Black"); dict.Add("Mud", "Brown"); var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType()); using (var stream = new MemoryStream()) { // Load memory stream with this objects xml representation XmlWriter xmlWriter = null; try { xmlWriter = XmlWriter.Create(stream); serializer.Serialize(xmlWriter, dict); } finally { xmlWriter.Close(); } // Rewind stream.Seek(0, SeekOrigin.Begin); XDocument doc = XDocument.Load(stream); Assert.AreEqual("Dictionary", doc.Root.Name); Assert.AreEqual(dict.Count, doc.Root.Descendants().Count()); // Rewind stream.Seek(0, SeekOrigin.Begin); var outDict = serializer.Deserialize(stream) as SerializableDictionary; Assert.AreEqual(dict["Grass"], outDict["Grass"]); Assert.AreEqual(dict["Snow"], outDict["Snow"]); Assert.AreEqual(dict["Sky"], outDict["Sky"]); } } [TestMethod] public void TestIntIntDict() { var dict = new SerializableDictionary(); dict.Add(4, 7); dict.Add(5, 9); dict.Add(7, 8); var serializer = new System.Xml.Serialization.XmlSerializer(dict.GetType()); using (var stream = new MemoryStream()) { // Load memory stream with this objects xml representation XmlWriter xmlWriter = null; try { xmlWriter = XmlWriter.Create(stream); serializer.Serialize(xmlWriter, dict); } finally { xmlWriter.Close(); } // Rewind stream.Seek(0, SeekOrigin.Begin); XDocument doc = XDocument.Load(stream); Assert.AreEqual("Dictionary", doc.Root.Name); Assert.AreEqual(3, doc.Root.Descendants().Count()); // Rewind stream.Seek(0, SeekOrigin.Begin); var outDict = serializer.Deserialize(stream) as SerializableDictionary; Assert.AreEqual(dict[4], outDict[4]); Assert.AreEqual(dict[5], outDict[5]); Assert.AreEqual(dict[7], outDict[7]); } } } }
la classe Dictionary implémente ISerializable. La définition du dictionnaire de classes ci-dessous.
[DebuggerTypeProxy(typeof(Mscorlib_DictionaryDebugView<,>))] [DebuggerDisplay("Count = {Count}")] [Serializable] [System.Runtime.InteropServices.ComVisible(false)] public class Dictionary: IDictionary, IDictionary, IReadOnlyDictionary, ISerializable, IDeserializationCallback
Je ne pense pas que ce soit le problème. reportez-vous au lien ci-dessous, qui indique que si vous avez un autre type de données qui n’est pas sérialisable, alors Dictionary ne sera pas sérialisé. http://forums.asp.net/t/1734187.aspx?Is+Dictionary+serializable+
Vous pouvez utiliser ExtendedXmlSerializer . Si vous avez un cours:
public class ConfigFile { public Ssortingng guiPath { get; set; } public ssortingng configPath { get; set; } public Dictionary mappedDrives {get;set;} public ConfigFile() { mappedDrives = new Dictionary(); } }
et créer une instance de cette classe:
ConfigFile config = new ConfigFile(); config.guiPath = "guiPath"; config.configPath = "configPath"; config.mappedDrives.Add("Mouse", "Logitech MX Master"); config.mappedDrives.Add("keyboard", "Microsoft Natural Ergonomic Keyboard 4000");
Vous pouvez sérialiser cet object en utilisant ExtendedXmlSerializer:
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer(); var xml = serializer.Serialize(config);
Le xml de sortie ressemblera à:
guiPath configPath -
Mouse Logitech MX Master -
keyboard Microsoft Natural Ergonomic Keyboard 4000
Vous pouvez installer ExtendedXmlSerializer à partir de nuget ou exécuter la commande suivante:
Install-Package ExtendedXmlSerializer
Voici l’ exemple en ligne
Cet article explique exactement comment gérer ceci: Comment sérialiser une table de hachage en C # lorsque l’application le requirejs?
J’espère que ceci est utile