2012-02-01 15 views
31

Ho un logger di chiamata che ha lo scopo di registrare tutte le chiamate di metodo insieme ai parametri associati al metodo utilizzando XmlSerializer. Funziona bene per la maggior parte delle chiamate, ma genera un'eccezione per tutti i metodi che hanno un parametro di tipo IEnumerable.XmlSerializer non serializza IEnumerable

Ad esempio, void MethodWithPlace(Place value) sarebbe serializzato, ma non lo sarebbe void MethodWithPlace(IEnumerable<Place> value).

L'eccezione è

System.NotSupportedException: Impossibile serializzare interfaccia System.Collections.Generic.IEnumerable`1 [[Luogo, prova, Version = 0.0.0.0, Culture = neutral]].

Cosa devo fare per farlo funzionare con questi metodi con IEnumerable come uno dei suoi parametri?

+2

può sostituire le definizioni dei metodi con un'implementazione concreta di IEnumerable, come ad esempio Lista ? –

+0

possibile duplicato di [Impossibile serializzare il parametro di tipo 'System.Linq.Enumerable ...' quando si utilizza WCF, LINQ, JSON] (http://stackoverflow.com/questions/2068897/cannot-serialize-parameter-of-type -system-linq-enumerable-when-using-wcf) – Coincoin

+0

possibile duplicazione di [Serialize Objects using xmlSerializer.Serialize e IEnumerable objects] (http://stackoverflow.com/questions/2729875/serialize-objects-using-xmlserializer-serialize-and-ienumerable-objects) –

risposta

9

Fondamentalmente un XmlSerializer non può serializzare un'interfaccia. La soluzione, quindi, è di darle un'istanza concreta per la serializzazione. A seconda di come funziona il vostro logger invocazione, vorrei considerare l'utilizzo di

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

Quello che abbiamo fatto è stato ottenere tutti i parametri del metodo possibili in una classe e inserirli come extraTypes nel costruttore di XmlSerializer. Quindi, creiamo un proxy trasparente per quella classe, acquisiamo le chiamate ai metodi, li serializziamo e invochiamo il metodo reale. – uni

8

non credo che sarete in grado di serializzare questo. Prova a convertire l'oggetto IEnumerable in un elenco e sarai in grado di serializzare.

+2

Poiché non riesco a modificare la firma del metodo, c'è qualche soluzione che può eventualmente risolvere questo problema? – uni

+2

È possibile se si dovesse semplicemente aggiungere la .ToList() a quel metodo Signature o dovrei dire se restituire l'IEnumberable.ToList() – MethodMan

+2

È possibile utilizzare un serializzatore diverso, come NetDataContractSerializer? Non sarai in grado di farlo con il serializzatore XML. – Joe

-1

XmlSerializer non supporta questo. Prova YAXLib per queste serializzazioni di tipi.

26

Il modo in cui si serializzare una proprietà IEnumerable è con una proprietà surrogata

[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; } } 
} 

E 'brutto, ma ottiene il lavoro fatto. La soluzione migliore è scrivere una classe surrogata (cioè EntitySurrogate).

+1

Lancio '[Browsable (false), EditorBrowsable (EditorBrowsableState.Never)]' sulla surrogata aiuterà a nasconderlo. Inoltre, potrebbe voler prendere in considerazione il pattern ShouldSerialize *. [Simile a questa risposta] (http://stackoverflow.com/a/10840603/425809). – Richard

3

Per essere serializzabili in XML, i tipi che ereditano da IEnumerable devono avere un'implementazione di Aggiungi (System.Object) a tutti i livelli della loro gerarchia di ereditarietà. {la tua classe} non implementa Aggiungi (System.Object).

implementare la funzione Add(), si potrebbe risolvere il problema

-1

È possibile utilizzare 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 domanda riguardava il Serializer XML, non il serializzatore del contratto dati. –

0

Forse non è il modo migliore, ma ha funzionato per me. Ho creato un metodo che rende la serializzazione.

Uso

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

metodo

 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; 

    } 
Problemi correlati