2009-05-30 14 views
7

Según tengo entendido, tengo que adornar a un nuevo miembro en una versión más nueva de mi clase con el atributo [OptionalField] cuando deserializo una versión anterior de mi clase que carece de este miembro más nuevo.¿Qué sucede con el atributo [OptionalField]?

Sin embargo, el código siguiente no arroja ninguna excepción mientras que la propiedad InnerTranslator se agregó después de serializar la clase. Compruebo que la propiedad sea nula en el método onDeserialization (que confirma que no fue serializada), pero esperaba que el código emitiera una excepción por eso. ¿El atributo [OptionalField] es opcional?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var listcol = new SortedList<string,string> 
     { 
      {"Estados Unidos", "United States"}, 
      {"Canadá", "Canada"}, 
      {"España", "Spain"} 
     }; 
     var translator = new CountryTranslator(listcol); 
     using (var file_stream=new FileStream("translator.bin",FileMode.Open)) 
     { 
      var formatter = new BinaryFormatter(); 
      translator = formatter.Deserialize(file_stream) as CountryTranslator; 
      file_stream.Close(); 
     } 
     Console.ReadLine(); 
    } 
} 

[Serializable] 
internal class CountryTranslator:IDeserializationCallback 
{ 
    public int Count { get; set; } 

    public CountryTranslator(SortedList<string,string> sorted_list) 
    { 
     this.country_list = sorted_list; 
     inner_translator = new List<string> {"one", "two"}; 
    } 
    //[OptionalField] 
    private List<string> inner_translator; 
    public List<string> InnerTranslator 
    { 
     get { return inner_translator; } 
     set { inner_translator = value; } 
    } 

    private SortedList<string, string> country_list; 

    public void OnDeserialization(object sender) 
    { 
     Debug.Assert(inner_translator == null); 
     Count=country_list.Count; 
    } 
} 
+0

Acabo de descubrir que el formateador SOAP lanza una excepción cuando el interior_translator no está adornado con el atributo [OptionalField] – Dabblernl

Respuesta

8

BinaryFormatter es, en el mejor de veces, muy frágil si cambia las cosas. No menos importante, hay grandes problemas con automatically implemented properties, obfuscaction, cambio de nombre, nombres fuertes, etc.

Como recuerdo, algunas de las reglas sobre [OptionalField] cambiaron justo antes de que se lanzara; la versión tolerante no funcionó tan fácilmente como se había planeado, supongo.

Mi consejo: si quiere una serialización tolerante a la versión (es decir, puede serializarla hoy y deserializarla con la próxima versión de su aplicación), entonces no use BinaryFormatter; esto es (IMO) solo adecuado para pasar datos entre misma versión (remota, AppDomain s, etc.).

Para trabajar entre versiones, recomiendo la serialización basada en contratos; cosas como XmlSerializer y DataContractSerializer (.NET 3.0), o para binario - protobuf-net o herramientas similares. Todos estos son mucho mejor en la tolerancia de versión (de hecho, ni siquiera es necesario deserializarlo en el mismo Type); Además, se pueden usar entre plataformas, para que pueda serializar en .NET y deserializar en java/C++/etc.

+0

No es exactamente la respuesta que estaba buscando, pero descubrí que he cambiado al uso del DataContractSerializer exclusivamente desde lo has sugerido en esta publicación. Así que gracias después de todo ;-) – Dabblernl

+0

¿Alguna vez usaría [OptionalField] para tipos de valores como Booleans o Integers? ¿O es este atributo solo relevante para los tipos de referencia como en la pregunta del OP? –

Cuestiones relacionadas