remarks comentarios c# properties xml-serialization xmlserializer

comentarios - remarks c#



La deserialización Xml se agrega a la lista (3)

Básicamente, así es como funciona XmlSerializer . A menos que la lista sea null , nunca espera intentar establecer un valor. En particular, la mayoría de las veces, las listas de subelementos no tienen un colocador; son cosas como:

private readonly List<Child> children = new List<Child>(); public List<Child> Children { get { return children; } }

(porque la mayoría de la gente no quiere que los llamadores externos reasignen la lista, solo quieren que cambien los contenidos).

Debido a esto, XmlSerializer funciona básicamente como (simplificación excesiva):

var list = yourObj.SomeList; foreach({suitable child found in the data}) list.Add({new item});

Una solución es usar una matriz en lugar de una lista; siempre espera asignar una matriz al objeto, por lo que para una matriz se implementa más como (simplificación excesiva):

var list = new List<SomeType>(); foreach({suitable child found in the data}) list.Add({new item}); yourObj.SomeList = list.ToArray();

Sin embargo, para un número fijo de valores, una implementación más simple podría ser simplemente:

public Foo Value1 {get;set;} public Foo Value2 {get;set;} public Foo Value3 {get;set;}

(si te das cuenta de lo que quiero decir)

Estoy tratando de deserializar algunas configuraciones de un archivo xml. La propiedad problemática / campo subyacente es una llamada AlertColors . Inicializo el campo subyacente en blanco, amarillo y rojo para asegurarme de que una nueva instancia de esta clase tenga una configuración de color válida. Pero cuando me deserializo, _colorArgb termina con seis valores, los tres primeros son los valores de inicialización y los tres últimos son los que se leen del archivo xml. Pero la propiedad AlertColors no se AlertColors al campo, sino que cambia sus elementos. ¿Por qué termino con un campo con seis colores?

Aquí está el código:

private List<int> _colorArgb = new List<int>(new int[] { Color.White.ToArgb(), Color.Yellow.ToArgb(), Color.Red.ToArgb() }); public List<int> AlertColors { get { return _colorArgb; } set { for (int i = 0; i < Math.Min(_colorArgb.Count, value.Count); i++) { if (_colorArgb[i] != value[i]) { HasChanged = true; } } _colorArgb = value; } } public bool Deserialize(string filePath) { if (!File.Exists(filePath)) { Logger.Log("Error while loading the settings. File does not exist."); return false; } FileStream fileStream = null; try { fileStream = new FileStream(filePath, FileMode.Open); System.Xml.Serialization.XmlSerializerFactory xmlSerializerFactory = new XmlSerializerFactory(); System.Xml.Serialization.XmlSerializer xmlSerializer = xmlSerializerFactory.CreateSerializer(typeof(Settings)); Settings deserializedSettings = (Settings)xmlSerializer.Deserialize(fileStream); GetSettings(deserializedSettings); Logger.Log("Settings have been loaded successfully from the file " + filePath); } catch (IOException iOException) { Logger.Log("Error while loading the settings. " + iOException.Message); return false; } catch (ArgumentException argumentException) { Logger.Log("Error while loading the settings. " + argumentException.Message); return false; } catch (InvalidOperationException invalidOperationException) { Logger.Log("Error while loading the settings. Settings file is not supported." + invalidOperationException.Message); return false; } finally { if (fileStream != null) fileStream.Close(); FilePath = filePath; } return true; } protected void GetSettings(Settings settings) { AlertColors = settings.AlertColors; }

Y la parte relevante del archivo xml que estoy deserializando:

<AlertColors> <int>-1</int> <int>-15</int> <int>-65536</int> </AlertColors>


Llegué un poco tarde a la fiesta, pero me encontré con este problema también.

La respuesta aceptada menciona que las matrices se asignan cada vez que ocurre una deserialización. Esto fue muy útil. Pero necesitaba una solución que no me requiriera cambiar el tipo de propiedades y reescribir un millón de líneas de código. Así que se me ocurrió esto:

Con los atributos de XML Serializer, puede "redirigir" el serializador a una matriz que envuelve la propiedad original.

[XmlIgnore] public List<int> AlertColors { get; set; } = new List<int>() { Color.White.ToArgb(), Color.Yellow.ToArgb(), Color.Red.ToArgb() }); [XmlArray(ElementName = "AlertColors")] public long[] Dummy { get { return AlertColors.ToArray(); } set { if(value != null && value.Length > 0) AlertColors = new List<int>(value); } }

La propiedad Dummy debe ser pública para que el serializador pueda acceder a ella. Para mí, sin embargo, este era un pequeño precio a pagar, sin modificar la propiedad original, así que no tuve que modificar ningún código adicional.


Para obtener el resultado deseado sin cambiar sus tipos de datos, puede usar un DataContractSerializer (utilizando System.Runtime.Serialization;) en lugar del XmlSerializer normal. No llama a los constructores por defecto, por lo que terminará con 3 colores en lugar de 6.

var ser = new DataContractSerializer(typeof(Settings)); var reader = new FileStream(@"c:/SettingsFile.xml", FileMode.Open); var deserializedSettings = (Settings)ser.ReadObject(reader);