2012-05-04 14 views
11

Ho riscontrato alcuni comportamenti sorprendenti utilizzando XmlSerializer in C#. Considera il seguente pezzo di codice..NET XmlSerializer e classi nidificate in C#

public class A : IEnumerable 
{ 
    public class B 
    { 
     [XmlAttribute] 
     public string PropA { get; set; } 
     [XmlElement] 
     public string PropB { get; set; } 
    } 

    public IEnumerator GetEnumerator() 
    { 
     yield break; 
    } 
} 

class Program 
{ 
    static void Main (string[] args) 
    { 
     XmlSerializer serializer = new XmlSerializer(typeof(A.B)); 

     XmlTextWriter writer = new XmlTextWriter(@"E:\temp\test.xml", Encoding.Default); 
     serializer.Serialize(writer, new A.B() { PropA = "one", PropB = "two" }); 
    } 
} 

In questo esempio provo a serializzare un'istanza di a.b classe nidificata, che di per sé non fa uso della classe contenitore A in alcun modo. Ma quando tento di costruire il XmlSerializer per esso, il seguente viene generata un'eccezione:

InvalidOperationException è stata gestita:

Per essere XML serializzabile, tipi che ereditano da IEnumerable deve avere un'implementazione di Add (Sistema .Oggetto) a tutti i livelli della loro gerarchia di ereditarietà . Test.A non implementa Aggiungi (System.Object).

XmlSerializer sta tentando di applicare i vincoli di serializzazione a tipo A quando sto provando a serializzare il tipo A.B. Tuttavia, la mia comprensione è che oltre all'accesso privilegiato ai dati nelle istanze del tipo esterno, un tipo annidato non è speciale e si comporta come se fosse in uno spazio dei nomi.

Questa interpretazione non è corretta e fa la semantica dei tipi nidificati o XmlSerializer giustifica questo comportamento o sembra un bug in XmlSerializer?

In particolare per quanto riguarda la semantica XmlSerializer, esistono requisiti documentati che impongono i vincoli XmlSerializer su tutti i tipi esterni quando applicati a un tipo annidato?

+1

Non si verifica un problema con i tipi nidificati. La tua classe A non ha una proprietà di tipo 'B'. –

+0

Inoltre, non utilizzare 'new XmlTextWriter()'. Questo è stato deprecato da .NET 2.0. Usa invece 'XmlWriter.Create()'. –

+3

Mi dispiace, ma tu hai perso completamente il punto della mia domanda. Non sto cercando di serializzare A, e non sto cercando di serializzare B come una proprietà di A. Sto provando a serializzarlo completamente indipendente da A. E sono consapevole della deprecazione di TextWriter. Questo è un esempio inventato dalla mia mente che ho cercato di mantenere breve. –

risposta

0

È l'IEnumerable che sta ponendo i vincoli qui. Se aggiungi il metodo Aggiungi come suggerito dall'eccezione, il tuo codice funzionerà correttamente. Ancora una volta questo ha poco a che fare con XmlSerialization e altro con il modo in cui IEnumerable funziona. Per favore correggimi se sono qui. Controlla this per una buona discussione sullo stesso.

+0

Ancora una volta, so qual è il vincolo e come risolverlo. La vera domanda è, perché questo vincolo viene applicato a un tipo che non sto provando a serializzare. L'altro vincolo che ho osservato come problema è il costruttore predefinito, anche se ho avuto più difficoltà a isolarlo con l'esempio. –

+0

Justin è corretto. Questo è un bug nel Serializer XML. Questo non è lo stesso problema della domanda che hai collegato. –

0

XmlSerializer offre un trattamento speciale alle classi che implementano IEnumerable o ICollection.

maggiori dettagli qui: XmlSerializer and IEnumerable: Serialization possible w/o parameterless constructor: Bug?

+0

Il punto dell'esempio che ho fornito è che la classe che implementa IEnumerable non è in realtà la classe che viene serializzata. La classe nidificata viene serializzata ed è completamente indipendente. Anche l'autore della risposta accettata della domanda che hai collegato sembra concordare sul fatto che si tratta di un bug. –

1

http://msdn.microsoft.com/en-us/library/vstudio/ms229027%28v=vs.100%29.aspx

Poiché un tipo annidato è trattato come un membro del tipo dichiarare, il tipo annidato ha accesso a tutti gli altri membri nel tipo dichiarare.

Quindi se il serializzatore vuole lavorare con A.B, ha bisogno anche della definizione di A. Dove i calci di validazione IEnumerable in.

Non importa che B in realtà non fare riferimento a qualcosa in un :)

0

Probabilmente questo è un problema molto difficile nella serializzazione in fase di esecuzione, ma non lo faccio avere una buona spiegazione di questo comportamento. Ritengo che la restrizione di IEnumerable non si applichi alla classe B.

Problemi correlati