¿Cómo serializar / deserializar a `Dictionary ` desde XML personalizado que no usa XElement?

Tener el Dictionary vacío Dictionary cómo llenarlo con claves y valores de XML como

    

y serializarlo nuevamente en XML que no usa XElement?

Con la ayuda de una clase de item temporal

 public class item { [XmlAttribute] public int id; [XmlAttribute] public string value; } 

Diccionario de muestra:

 Dictionary dict = new Dictionary() { {1,"one"}, {2,"two"} }; 

.

 XmlSerializer serializer = new XmlSerializer(typeof(item[]), new XmlRootAttribute() { ElementName = "items" }); 

Publicación por entregas

 serializer.Serialize(stream, dict.Select(kv=>new item(){id = kv.Key,value=kv.Value}).ToArray() ); 

Deserialización

 var orgDict = ((item[])serializer.Deserialize(stream)) .ToDictionary(i => i.id, i => i.value); 

————————————————– —————————-

Así es cómo se puede hacer usando XElement , si cambia de opinión.

Publicación por entregas

 XElement xElem = new XElement( "items", dict.Select(x => new XElement("item",new XAttribute("id", x.Key),new XAttribute("value", x.Value))) ); var xml = xElem.ToString(); //xElem.Save(...); 

Deserialización

 XElement xElem2 = XElement.Parse(xml); //XElement.Load(...) var newDict = xElem2.Descendants("item") .ToDictionary(x => (int)x.Attribute("id"), x => (string)x.Attribute("value")); 

El blog ASP.NET de Paul Welter tiene un diccionario serializable. Pero no usa atributos. Explicaré por qué debajo del código.

 using System; using System.Collections.Generic; using System.Text; using System.Xml.Serialization; [XmlRoot("dictionary")] public class SerializableDictionary : Dictionary, IXmlSerializable { #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; reader.ReadStartElement("item"); while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { 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.MoveToContent(); } reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); writer.WriteStartElement("item"); foreach (TKey key in this.Keys) { 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 } 

Primero, hay un gotcha con este código. Digamos que lees un diccionario de otra fuente que tiene esto:

    key1   value1     key1   value2    

Esto generará una excepción en la eliminación de la selación porque solo puede tener una clave para un diccionario.


La razón por la que DEBE usar un elemento XElement en un diccionario seriazed es que el diccionario no está definido como Dictionary , un diccionario es Dictionary .

Para ver el problema, pregúntate a TValue mismo: digamos que tenemos un TValue que se serializa en algo que usa Elements se describe a sí mismo como XML (digamos un diccionario de diccionarios Dictionary> (no tan raro) de un patrón, es una tabla de búsqueda), ¿cómo representaría su versión de Atributo solo un diccionario completamente dentro de un atributo?

Los diccionarios no se pueden serializar en C # por defecto, no sé por qué, pero parece haber sido una elección de diseño.

En este momento, recomendaría usar Json.NET para convertirlo a JSON y de ahí a un diccionario (y viceversa). A menos que realmente necesite el XML, le recomendaría usar JSON por completo.

Tengo una estructura KeyValuePairSerializable :

 [Serializable] public struct KeyValuePairSerializable { public KeyValuePairSerializable(KeyValuePair pair) { Key = pair.Key; Value = pair.Value; } [XmlAttribute] public K Key { get; set; } [XmlText] public V Value { get; set; } public override string ToString() { return "[" + StringHelper.ToString(Key, "") + ", " + StringHelper.ToString(Value, "") + "]"; } } 

Entonces, la serialización XML de una propiedad del Dictionary es por:

 [XmlIgnore] public Dictionary Parameters { get; set; } [XmlArray("Parameters")] [XmlArrayItem("Pair")] [DebuggerBrowsable(DebuggerBrowsableState.Never)] // not necessary public KeyValuePairSerializable[] ParametersXml { get { return Parameters?.Select(p => new KeyValuePairSerializable(p)).ToArray(); } set { Parameters = value?.ToDictionary(i => i.Key, i => i.Value); } } 

Solo la propiedad debe ser la matriz, no la Lista.

Escriba una clase A, que contenga una matriz de clase B. La clase B debe tener una propiedad de identificación y una propiedad de valor. Deserialice el xml a la clase A. Convierta la matriz en A en el diccionario deseado.

Para serializar el diccionario conviértalo en una instancia de clase A, y serializar …

Basado en la respuesta de LB.

Uso:

 var serializer = new DictionarySerializer(); serializer.Serialize("dictionary.xml", _dictionary); _dictionary = _titleDictSerializer.Deserialize("dictionary.xml"); 

Clase genérica:

 public class DictionarySerializer { [XmlType(TypeName = "Item")] public class Item { [XmlAttribute("key")] public TKey Key; [XmlAttribute("value")] public TValue Value; } private XmlSerializer _serializer = new XmlSerializer(typeof(Item[]), new XmlRootAttribute("Dictionary")); public Dictionary Deserialize(string filename) { using (FileStream stream = new FileStream(filename, FileMode.Open)) using (XmlReader reader = XmlReader.Create(stream)) { return ((Item[])_serializer.Deserialize(reader)).ToDictionary(p => p.Key, p => p.Value); } } public void Serialize(string filename, Dictionary dictionary) { using (var writer = new StreamWriter(filename)) { _serializer.Serialize(writer, dictionary.Select(p => new Item() { Key = p.Key, Value = p.Value }).ToArray()); } } } 

Utilizo las clases serializables para la comunicación WCF entre diferentes módulos. A continuación se muestra un ejemplo de clase serializable que también sirve como DataContract. Mi enfoque es utilizar el poder de LINQ para convertir el diccionario en listas serializables listas para usar <> de KeyValuePair <>:

  using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Xml.Serialization; namespace MyFirm.Common.Data { [DataContract] [Serializable] public class SerializableClassX { // since the Dictionary<> class is not serializable, // we convert it to the List> [XmlIgnore] public Dictionary DictionaryX { get { return SerializableList == null ? null : SerializableList.ToDictionary(item => item.Key, item => item.Value); } set { SerializableList = value == null ? null : value.ToList(); } } [DataMember] [XmlArray("SerializableList")] [XmlArrayItem("Pair")] public List> SerializableList { get; set; } } } 

El uso es sencillo: asigno un diccionario al campo del diccionario de mi objeto de datos, DictionaryX. La serialización se admite dentro de SerializableClassX mediante la conversión del diccionario asignado en la lista serializable <> de KeyValuePair <>:

  // create my data object SerializableClassX SerializableObj = new SerializableClassX(param); // this will call the DictionaryX.set and convert the ' // new Dictionary into SerializableList SerializableObj.DictionaryX = new Dictionary { {"Key1", 1}, {"Key2", 2}, }; 

Puede usar ExtendedXmlSerializer . Si tienes una clase:

 public class TestClass { public Dictionary Dictionary { get; set; } } 

y crea una instancia de esta clase:

 var obj = new TestClass { Dictionary = new Dictionary { {1, "First"}, {2, "Second"}, {3, "Other"}, } }; 

Puede serializar este objeto usando ExtendedXmlSerializer:

 var serializer = new ConfigurationContainer() .UseOptimizedNamespaces() //If you want to have all namespaces in root element .Create(); var xml = serializer.Serialize( new XmlWriterSettings { Indent = true }, //If you want to formated xml obj); 

El resultado xml se verá así:

     1 First   2 Second   3 Other    

Puede instalar ExtendedXmlSerializer desde nuget o ejecutar el siguiente comando:

 Install-Package ExtendedXmlSerializer 

Hay una manera fácil con Sharpeserializer (fuente abierta):

http://www.sharpserializer.com/

Puede serializar / deserializar diccionario directamente.

No es necesario marcar su objeto con ningún atributo, ni debe dar el tipo de objeto en el método Serializar (consulte aquí ).

Para instalar a través de nuget: Install-package sharpserializer

Entonces es muy simple:

Hello World (del sitio web oficial):

 // create fake obj var obj = createFakeObject(); // create instance of sharpSerializer // with standard constructor it serializes to xml var serializer = new SharpSerializer(); // serialize serializer.Serialize(obj, "test.xml"); // deserialize var obj2 = serializer.Deserialize("test.xml");