2012-03-06 16 views
10

Sto notando un comportamento strano con XmlSerializer e elenchi generici (in particolare List<int>). Mi stavo chiedendo se qualcuno l'ha mai visto prima o sa cosa sta succedendo. Sembra che la serializzazione funzioni bene, ma la deserializzazione vuole aggiungere elementi extra alla lista. Il seguente codice illustra il problema.Elenco deserializzazione <int> con XmlSerializer Causando elementi aggiuntivi

classe Serializable: codice

public class ListTest 
{ 
    public int[] Array { get; set; } 
    public List<int> List { get; set; } 

    public ListTest() 
    { 
     Array = new[] {1, 2, 3, 4}; 
     List = new List<int>(Array); 
    } 
} 

Test: uscita

ListTest listTest = new ListTest(); 
Debug.WriteLine("Initial Array: {0}", (object)String.Join(", ", listTest.Array)); 
Debug.WriteLine("Initial List: {0}", (object)String.Join(", ", listTest.List)); 

XmlSerializer serializer = new XmlSerializer(typeof(ListTest)); 
StringBuilder xml = new StringBuilder(); 
using(TextWriter writer = new StringWriter(xml)) 
{ 
    serializer.Serialize(writer, listTest); 
} 

Debug.WriteLine("XML: {0}", (object)xml.ToString()); 

using(TextReader reader = new StringReader(xml.ToString())) 
{ 
    listTest = (ListTest) serializer.Deserialize(reader); 
} 

Debug.WriteLine("Deserialized Array: {0}", (object)String.Join(", ", listTest.Array)); 
Debug.WriteLine("Deserialized List: {0}", (object)String.Join(", ", listTest.List)); 

Debug:

Initial Array: 1, 2, 3, 4 
Initial List: 1, 2, 3, 4 

XML:

<?xml version="1.0" encoding="utf-16"?> 
<ListTest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Array> 
    <int>1</int> 
    <int>2</int> 
    <int>3</int> 
    <int>4</int> 
    </Array> 
    <List> 
    <int>1</int> 
    <int>2</int> 
    <int>3</int> 
    <int>4</int> 
    </List> 
</ListTest> 
Deserialized Array: 1, 2, 3, 4 
Deserialized List: 1, 2, 3, 4, 1, 2, 3, 4 

Si noti che sia la matrice che l'elenco sembrano essere serializzati su XML in modo corretto ma in fase di deserializzazione la matrice risulta corretta ma l'elenco ritorna con un insieme di elementi duplicati. Qualche idea?

+1

Grazie per le risposte - come ho già detto in un commento qui sotto, non mi rendevo conto del deserializzatore è stato in grado di mutare lo stato dei membri durante la deserializzazione (nella maggior parte dei casi penso che solo stabilisce nuovi valori, giusto?). L'elenco è l'unica classe con cui può farlo? C'è qualche riferimento che indichi quali classi possono essere mutate dal deserializzatore? – daveaglick

risposta

7

Succede perché si sta inizializzando l'elenco nel costruttore. Quando si va a deserializzare, viene creato un nuovo ListTest e quindi popola l'oggetto dallo stato.

Pensate al flusso di lavoro come questo

  1. Creare un nuovo ListTest
  2. Eseguire il Costruttore (aggiungi 1,2,3,4)
  3. deserializzare lo stato xml, e aggiungere 1,2, 3,4 alla lista

Una soluzione semplice sarebbe quella di inizializzare l'oggetto al di fuori dell'ambito del costruttore.

public class ListTest 
{ 
    public int[] Array { get; set; } 
    public List<int> List { get; set; } 

    public ListTest() 
    { 

    } 

    public void Init() 
    { 
     Array = new[] { 1, 2, 3, 4 }; 
     List = new List<int>(Array); 
    } 
} 

ListTest listTest = new ListTest(); 
listTest.Init(); //manually call this to do the initial seed 
3

Il problema è che si sta definendo l'1,2,3,4 originale nell'Elenco nel costruttore predefinito. Il tuo deserializzatore si aggiunge alla lista, non la definisce.

+3

Grazie, spostare l'inizializzazione dal costruttore ha effettivamente risolto il problema. Ho frainteso come funziona il deserializzatore. Non avevo realizzato che muta oggetti esistenti, pensavo che usasse sempre l'accessor set per scrivere istanze completamente nuove di bambini all'oggetto appena costruito (nel qual caso l'elenco creato nel costruttore sarebbe stato appena dimenticato). Impari qualcosa ogni giorno – daveaglick

Problemi correlati