2010-11-18 18 views
11

Observé un comportamiento extraño al serializar y deserializar una clase que tiene un miembro del tipo List<T> que se llenó con valores predeterminados en tiempo de construcción. A diferencia de la propiedad basada en matrices, la propiedad del tipo List<T> no se vaciará en la deserialización por XmlSerializer.XmlSerializer y List <T> con valores predeterminados

Aquí está mi código:

public class Program 
{ 
    public class Config 
    { 
     public Config() 
     { 
      Test1 = new List<string>() {"A", "B"}; 
      Test2 = new String[] {"A", "B"}; 
     } 
     public List<string> Test1 {get;set;} 
     public string[] Test2 {get;set;} 
    } 

    public static void Main() 
    { 
     XmlSerializer xmlSerializer = 
      new XmlSerializer(typeof(Config)); 
     using(Stream s = new MemoryStream()) 
     { 
      xmlSerializer.Serialize(s, new Config()); 
      s.Position = 0; 
      xmlSerializer.Serialize(Console.Out, 
       xmlSerializer.Deserialize(s)); 
     } 
    } 
} 

Y esta es la salida:

<?xml version="1.0" encoding="ibm850"?> 
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Test1> 
    <string>A</string> 
    <string>B</string> 
    <string>A</string> 
    <string>B</string> 
    </Test1> 
    <Test2> 
    <string>A</string> 
    <string>B</string> 
    </Test2> 
</Config> 

¿Por qué es el List<T> manejado de manera diferente por XmlSerializer de la matriz y qué se puede hacer para cambiar este comportamiento?

+0

tengo problema de semejanza, veo http://stackoverflow.com/questions/5221124/hook-in-to-ondeserializing-for-xmlserializer para la solución –

+0

relacionados: http://stackoverflow.com/q/ 13046474/161052 – JYelton

Respuesta

5

Interesante; Nunca lo había notado en el pasado, pero definitivamente es reproducible. Como el XmlSerializer no es compatible con las devoluciones de llamadas de serialización (para ayudarlo a saber que se está ejecutando para la serialización), es difícil influir; Podría decirse que la respuesta más simple es "no coloque datos predeterminados en los objetos en el constructor" (aunque tal vez ofrezca un método de fábrica que lo haga).

Usted podría intente implementar IXmlSerializable, pero eso es demasiado difícil de conseguir, incluso para un ejemplo simple.

He comprobado, sin embargo, y DataContractSerializer no comportarse de esta manera - por lo que tal vez podría cambiar a DataContractSerializer; aquí está mi código de prueba con DCS:

DataContractSerializer ser = 
    new DataContractSerializer(typeof(Config)); 
using (Stream s = new MemoryStream()) 
{ 
    ser.WriteObject(s, new Config()); 
    s.Position = 0; 
    using(var writer = XmlWriter.Create(Console.Out)) { 
     ser.WriteObject(writer, ser.ReadObject(s)); 
    } 
} 

y aquí está lo que quiero decir por un método de fábrica:

public class Config 
{ 
    public Config() 
    { 
     Test1 = new List<string>(); 
     Test2 = nix; 
    } 
    public List<string> Test1 { get; set; } 
    public string[] Test2 { get; set; } 

    private static readonly string[] nix = new string[0]; 
    public static Config CreateDefault() 
    { 
     Config config = new Config(); 
     config.Test1.Add("A"); 
     config.Test1.Add("B"); 
     config.Test2 = new string[2] { "A", "B" }; 
     return config; 
    } 
} 
+0

este es un comportamiento muy interesante .... –

3

Este es de hecho el comportamiento de la frustración de deserialización XML cuando las listas contienen un conjunto de entradas por defecto creado en el constructor

Mi solución fue establecer XMLIgnoreAttribute en la lista e incluir un miembro público de una matriz del tipo de objeto con el conjunto/get manejando la población de la lista de la matriz.

Algo como lo siguiente permite crear valores predeterminados en el constructor, pero evita que el serializador XML agregue entradas a la lista predeterminada. (validaciones de error/nul aparte).

public class Config 
{ 
    public Config() 
    { 
     Test1 = new List<string>() { "A", "B" }; 
     Test2 = new String[] { "A", "B" }; 

    } 

    [XmlIgnore] 
    public List<string> Test1 { get; set; } 
    public string[] Test2 { get; set; } 

    // This member is only to be used during XML serialization 
    public string[] Test1_Array 
    { 
     get 
     { 
      return Test1.ToArray(); 
     } 
     set 
     { 
      Test1 = value.ToList(); 
     } 
    }   

} 
Cuestiones relacionadas