2010-03-30 26 views
9

Aquí es mi clase:¿Cómo deserializar la matriz nula para anular en C#?

public class Command 
{ 
    [XmlArray(IsNullable = true)] 
    public List<Parameter> To { get; set; } 
} 

Cuando serializar un objeto de esta clase:

var s = new XmlSerializer(typeof(Command)); 
s.Serialize(Console.Out, new Command()); 

se imprime como (se omiten los espacios de nombres de cabecera xml y por defecto MS) que se espera:

<Command><To xsi:nil="true" /></Command> 

Cuando tomé este xml e intenté deserializarlo, quedé trabado, porque siempre imprime "No nulo":

var t = s.Deserialize(...); 
if (t.To == null) 
    Console.WriteLine("Null"); 
else 
    Console.WriteLine("Not null"); 

Cómo forzar deserializer para hacer que mi lista sea nula, si es nula en xml?

+0

¿Es realmente tan importante para usted si usted no tiene ninguna lista o una lista vacía? –

+0

Sí. Puedo solucionar este caso con algunas banderas, por supuesto, pero quiero saber si hay una buena solución estándar. –

+1

Evitar objetos nulos suele ser algo bueno (menos propenso a errores, no hay necesidad de comprobar nulo en todo el código, etc.). Usar una bandera indicaría claramente qué representa exactamente ese valor nulo. – Groo

Respuesta

2

Uf, no es molesto eso. Puede verlo haciendo ejecutar sgen.exe en su ensamblado con las opciones/keep y/debug para que pueda depurar el código de deserialización. Se ve más o menos así:

global::Command o; 
o = new global::Command(); 
if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
global::System.Collections.Generic.List<global::Parameter> a_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
// code elided 
//... 
while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) { 
    if (Reader.NodeType == System.Xml.XmlNodeType.Element) { 
    if (((object)Reader.LocalName == (object)id4_To && (object)Reader.NamespaceURI == (object)id2_Item)) { 
     if (!ReadNull()) { 
     if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
     global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
     // code elided 
     //... 
     } 
     else { 
     // Problem here: 
     if ((object)([email protected]) == null) [email protected] = new global::System.Collections.Generic.List<global::Parameter>(); 
     global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)[email protected]; 
     } 
    } 
    } 
    Reader.MoveToContent(); 
    CheckReaderCount(ref whileIterations1, ref readerCount1); 
} 
ReadEndElement(); 
return o; 

No menos de 3 lugares donde se asegura la propiedad @Al no es nulo. El primero es algo defendible, difícil de deserializar los datos cuando la estructura no existe. El segundo hace la prueba nula otra vez, ese es el único realmente bueno. El tercero es el problema, ReadNull() devolvió verdadero pero todavía crea un valor de propiedad no nulo.

Si desea diferenciar entre vacío y nulo, entonces no tiene una buena solución pero edite este código a mano. Haga esto solo si realmente está desesperado y la clase es 100% estable. Bueno, no lo hagas. La solución de João es la única buena.

+0

Gracias. Agregaré banderas. –

0

Estoy de acuerdo con el comentario de @ Oliver, pero puede resolverlo de esta manera si lo necesita para que sea nulo. En lugar de usar una propiedad automática, crea tu propio campo de respaldo.

List<Parameter> _to; 
public List<Parameter> To 
{ 
    get 
    { 
     if (_to != null && _to.Count == 0) return null; 
     return _to; 
    } 
    set { _to = value; } 
} 
+0

Creo que OP quería * diferenciar * listas nulas y vacías. – Groo

+0

Desafortunadamente, en mi caso, la lista vacía y la lista nula son diferentes. –

+0

Eso lo hace más complicado de inmediato :( –

0

Si realmente necesita una colección que se deserializa a null cuando no se proporcionan valores puede hacerlo al no proporcionar un descriptor de acceso set, así:

public class Command 
{ 
    private List<Parameter> to; 

    public List<Parameter> To { get { return this.to; } } 
} 
+0

Mala opción. "Hasta" siempre será nulo después de la deserialización. –

3

Si se utiliza una matriz en lugar de una lista funciona como se esperaba

public class Command 
{ 
    [XmlArray(IsNullable = true)] 
    public Parameter[] To { get; set; } 
} 
Cuestiones relacionadas