2012-02-01 23 views
31

Tengo un registrador de invocación que está destinado a registrar todas las llamadas al método junto con los parámetros asociados con el método que utiliza XmlSerializer. Funciona bien para la mayoría de las llamadas, pero arroja una excepción para todos los métodos que tienen un parámetro del tipo IEnumerable. Por ejemplo, void MethodWithPlace(Place value) sería serializado, pero void MethodWithPlace(IEnumerable<Place> value) no lo haría.XmlSerializer no serializará IEnumerable

La excepción es

System.NotSupportedException: No se puede serializar interfaz System.Collections.Generic.IEnumerable`1 [[Place, de prueba, versión = 0.0.0.0, Culture = neutral]].

¿Qué debo hacer para que funcione con esos métodos con IEnumerable como uno de sus parámetros?

+2

Se puede reemplazar las definiciones de método con una aplicación concreta de IEnumerable, como la lista ? –

+0

posible duplicado de [No se puede serializar el parámetro del tipo 'System.Linq.Enumerable ...' cuando se usa WCF, LINQ, JSON] (http://stackoverflow.com/questions/2068897/cannot-serialize-parameter-of-type -system-linq-enumerable-when-using-wcf) – Coincoin

+0

posible duplicado de [Serializar objetos usando xmlSerializer.Objetos Serialize e IEnumerable] (http://stackoverflow.com/questions/2729875/serialize-objects-using-xmlserializer-serialize-and-ienumerable-objects) –

Respuesta

9

Básicamente, un XmlSerializer no puede serializar una interfaz. La solución, entonces, es darle una instancia concreta para serializar. Dependiendo de cómo funciona el registrador de invocación, me gustaría considerar el uso de

var serializer = new XmlSerializer(value.GetType()); 
+0

Lo que hicimos fue obtener todos los parámetros de métodos posibles en una clase y ponerlos como extraTypes en el constructor de XmlSerializer. Luego, creamos un proxy transparente para esa clase, capturamos llamadas a métodos, las serializamos e invocamos el método real. – uni

8

no creo que usted será capaz de serializar eso. Intenta convertir IEnumerable en una lista y luego podrás serializar.

+2

Como no puedo cambiar la firma del método, ¿hay alguna solución que pueda resolver este problema? – uni

+2

Puede si acaba de agregar el .ToList() a la firma de método o debería decir que lo devuelva IEnumberable.ToList() – MethodMan

+2

¿Puede utilizar un serializador diferente, como el NetDataContractSerializer? No podrá hacerlo con el serializador XML. – Joe

-1

XmlSerializer no es compatible con esto. Pruebe YAXLib para estas serializaciones de tipos.

26

La forma en que serializa una propiedad IEnumerable es decir, con una propiedad sustituta

[XmlRoot] 
public class Entity { 
    [XmlIgnore] 
    public IEnumerable<Foo> Foo { get; set; } 

    [XmlElement, Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
    public List<Foo> FooSurrogate { get { return Foo.ToList(); } set { Foo = value; } } 
} 

Es feo, pero hace el trabajo. La mejor solución es escribir una clase sustituta (es decir, EntitySurrogate).

+1

Al tirar '[Browsable (false), EditorBrowsable (EditorBrowsableState.Never)]' en el sustituto ayudará a ocultarlo. Además, es posible que desee considerar el patrón ShouldSerialize *. [Similar a esta respuesta] (http://stackoverflow.com/a/10840603/425809). – Richard

3

Para ser XML serializable, los tipos que se heredan de IEnumerable deben tener una implementación de Add (System.Object) en todos los niveles de su jerarquía de herencia. {su clase} no implementa Add (System.Object).

implementar la función Add(), es posible resolver el problema

-1

Puede utilizar DataContractSerializer

 using (var ms = new MemoryStream()) 
     { 
      var serialiser = new DataContractSerializer(typeof (EnvironmentMetadata)); 
      serialiser.WriteObject(ms, environmentMetadata); 

      var s = Encoding.ASCII.GetString(ms.ToArray()); 
      return s; 
     } 
+2

La pregunta era sobre el Serializador XML, no el serializador de contrato de datos. –

0
Tal vez no

la mejor manera, pero funcionó para mí. Creé un método que hace la serialización.

Uso

var xml = Util.ObjetoToXML (obj, null, null) .OuterXml;

método

 public static XmlDocument ObjetoToXML(object obj, XmlDocument xmlDocument, XmlNode rootNode) 
    { 

     if (xmlDocument == null) 
      xmlDocument = new XmlDocument(); 

     if (obj == null) return xmlDocument; 

     Type type = obj.GetType(); 

     if (rootNode == null) { 
      rootNode = xmlDocument.CreateElement(string.Empty, type.Name, string.Empty); 
      xmlDocument.AppendChild(rootNode); 
     } 

     if (type.IsPrimitive || type == typeof(Decimal) || type == typeof(String) || type == typeof(DateTime)) 
     { 

      // Simples types 
      if (obj != null) 
       rootNode.InnerText = obj.ToString(); 

     } 
     else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) 
     { 
      // Genericis types 

      XmlNode node = null; 

      foreach (var item in (IEnumerable)obj) 
      { 
       if (node == null) 
       { 
        node = xmlDocument.CreateElement(string.Empty, item.GetType().Name, string.Empty); 
        node = rootNode.AppendChild(node); 
       } 


       ObjetoToXML(item, xmlDocument, node); 
      } 

     } 
     else 
     { 

      // Classes types 
      foreach (var propertie in obj.GetType().GetProperties()) 
      { 

       XmlNode node = xmlDocument.CreateElement(string.Empty, propertie.Name, string.Empty); 
       node = rootNode.AppendChild(node); 
       var valor = propertie.GetValue(obj, null); 

       ObjetoToXML(valor, xmlDocument, node); 
      } 

     } 


     return xmlDocument; 

    } 
Cuestiones relacionadas