2010-01-13 17 views
11

En el código de ejemplo a continuación, me sale este error :¿Cómo puedo serializar un objeto con una propiedad Dictionary <string, object>?

Elemento TestSerializeDictionary123.Customer.CustomProperties vom Typ System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [System.Object, mscorlib, versión = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] puede no ser serializado porque implementa IDictionary.

Cuando saco la propiedad diccionario, funciona bien .

¿Cómo puedo serializar este objeto del Cliente con la propiedad del diccionario? ¿O qué tipo de reemplazo para Diccionario puedo usar que sería serializable?

using System; 
using System.Collections.Generic; 
using System.Xml.Serialization; 
using System.IO; 
using System.Xml; 
using System.Text; 

namespace TestSerializeDictionary123 
{ 
    public class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Customer> customers = Customer.GetCustomers(); 

      Console.WriteLine("--- Serializing ------------------"); 

      foreach (var customer in customers) 
      { 
       Console.WriteLine("Serializing " + customer.GetFullName() + "..."); 
       string xml = XmlHelpers.SerializeObject<Customer>(customer); 
       Console.WriteLine(xml); 
       Console.WriteLine("Deserializing ..."); 
       Customer customer2 = XmlHelpers.DeserializeObject<Customer>(xml); 
       Console.WriteLine(customer2.GetFullName()); 
       Console.WriteLine("---"); 
      } 

      Console.ReadLine(); 
     } 
    } 

    public static class StringHelpers 
    { 
     public static String UTF8ByteArrayToString(Byte[] characters) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      String constructedString = encoding.GetString(characters); 
      return (constructedString); 
     } 

     public static Byte[] StringToUTF8ByteArray(String pXmlString) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      Byte[] byteArray = encoding.GetBytes(pXmlString); 
      return byteArray; 
     } 
    } 

    public static class XmlHelpers 
    { 
     public static string SerializeObject<T>(object o) 
     { 
      MemoryStream ms = new MemoryStream(); 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); 
      xs.Serialize(xtw, o); 
      ms = (MemoryStream)xtw.BaseStream; 
      return StringHelpers.UTF8ByteArrayToString(ms.ToArray()); 
     } 

     public static T DeserializeObject<T>(string xml) 
     { 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml)); 
      XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8); 
      return (T)xs.Deserialize(ms); 
     } 
    } 

    public class Customer 
    { 
     public int Id { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string Street { get; set; } 
     public string Location { get; set; } 
     public string ZipCode { get; set; } 
     public Dictionary<string,object> CustomProperties { get; set; } 

     private int internalValue = 23; 

     public static List<Customer> GetCustomers() 
     { 
      List<Customer> customers = new List<Customer>(); 
      customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" }); 
      customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" }); 
      customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" }); 
      customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" }); 
      customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" }); 
      return customers; 
     } 

     public string GetFullName() 
     { 
      return FirstName + " " + LastName + "(" + internalValue + ")"; 
     } 

    } 
} 

Respuesta

14

En nuestra aplicación terminamos usando:

DataContractSerializer xs = new DataContractSerializer(typeof (T)); 

en lugar de:

XmlSerializer xs = new XmlSerializer(typeof (T)); 

que resolvió el problema, ya que es compatible con DataContractSerializer diccionario.

Otra solución es la solución XML Serializable Generic Dictionary también funciona en el ejemplo anterior, y hay una discusión larga en ese enlace de las personas que lo usan, puede ser útil para las personas que trabajan con este problema.

+0

Si bien el DataContractSerializer es una buena sugerencia, no cubre todos los escenarios y definitivamente no ofrece el mismo nivel de granularidad y definición que XmlSerializer. –

0

me acaba de encontrar esta blog post by Rakesh Rajan que describe una posible solución:

Anulación XmlSerialization haciendo que el tipo de implementar la clase System.Xml.Serialization.IXmlSerializable. Defina cómo desea que se serialice el objeto en XML en el método WriteXml y defina cómo puede volver a crear el objeto a partir de una cadena xml en el método ReadXml.

Pero esto no iba a funcionar como su diccionario contiene un object en lugar de un tipo específico.

4

No puede (a menos que lo haga todo usted mismo, lo cual es horrible); el serializador xml no va a tener una idea de qué hacer con object, ya que no incluye los metadatos de tipo en el formato de conexión. Una opción (hacky) sería transmitir todo esto como cadenas a los efectos de la serialización, pero luego tienes que escribir un gran número de código extra de análisis (etc).

+0

Voy a tener que rechazarlo, por sugerir que no se puede hacer. Se deriva de la interpretación de esta pregunta como querer Serialización XML solamente, pero sin embargo, creo que debería, solo para hacer mi parte para evitar una posible información errónea :) Afortunadamente, el OP puede aclarar si solo quiere la Serialización XML, o su publicación puede ser ajustado en consecuencia. –

+0

La etiqueta de serialización xml está en la pregunta, lo que sugiere que OP está interesado en la serialización XML. –

0

Qué tal marcar la clase de Cliente como DataContract y sus propiedades como DataMembers. El serializador de DataContract hará la serialización por usted.

1

En su lugar, puede usar Binary serialization. (Solo asegúrese de que todas sus clases estén marcadas como [Serializable].Por supuesto, no va a estar en formato XML, pero no una lista que, como requisito :)

9

Aquí es un genérico de clase diccionario que sabe cómo serializar sí:

public class XmlDictionary<T, V> : Dictionary<T, V>, IXmlSerializable { 
    [XmlType("Entry")] 
    public struct Entry { 
     public Entry(T key, V value) : this() { Key = key; Value = value; } 
     [XmlElement("Key")] 
     public T Key { get; set; } 
     [XmlElement("Value")] 
     public V Value { get; set; } 
    } 
    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { 
     return null; 
    } 
    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { 
     this.Clear(); 
     var serializer = new XmlSerializer(typeof(List<Entry>)); 
     reader.Read(); // Why is this necessary? 
     var list = (List<Entry>)serializer.Deserialize(reader); 
     foreach (var entry in list) this.Add(entry.Key, entry.Value); 
     reader.ReadEndElement(); 
    } 
    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { 
     var list = new List<Entry>(this.Count); 
     foreach (var entry in this) list.Add(new Entry(entry.Key, entry.Value)); 
     XmlSerializer serializer = new XmlSerializer(list.GetType()); 
     serializer.Serialize(writer, list); 
    } 
    } 
+0

Esto no resuelve el problema de tener un diccionario donde los valores son 'objeto'. – jsirr13

0

Trate a través Serializating BinaryFormatter

private void Deserialize() 
    { 
     try 
     { 
      var f_fileStream = File.OpenRead(@"dictionarySerialized.xml"); 
      var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
      myDictionary = (Dictionary<string, myClass>)f_binaryFormatter.Deserialize(f_fileStream); 
      f_fileStream.Close(); 
     } 
     catch (Exception ex) 
     { 
      ; 
     } 
    } 
    private void Serialize() 
    { 
     try 
     { 
      var f_fileStream = new FileStream(@"dictionarySerialized.xml", FileMode.Create, FileAccess.Write); 
      var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
      f_binaryFormatter.Serialize(f_fileStream, myDictionary); 
      f_fileStream.Close(); 
     } 
     catch (Exception ex) 
     { 
      ; 
     } 
    } 
Cuestiones relacionadas