2012-04-19 7 views
6

tengo esta claseEstrategia para deserializar una clase que ha cambiado en .NET

[Serializable] 
public class myClass() : ISerializable 
{ 
    public int a; 
    public int b; 
    public int c; 

    public void GetObjectData(SerializationInfo info, 
           StreamingContext context) 
     { 
     // Some code 
     } 

    public myClass(SerializationInfo info, 
        StreamingContext context) 
     { 
     // Some code 
     } 
} 

Tengo cientos de estos objetos en mi base de datos. Ahora estoy listo para publicar una nueva versión de mi aplicación donde la clase se ha transformado a

[Serializable] 
public class myClass() : ISerializable 
{ 
    public int a; 
    public string b; 
    public int c; 
    public bool d; 

    public void GetObjectData(SerializationInfo info, 
           StreamingContext context) 
     { 
     // Some code 
     } 

    public myClass(SerializationInfo info, 
        StreamingContext context) 
     { 
     // Some code 
     } 
} 

¿Cómo se podría deserializar un objeto serializado en base a la primera versión con el constructor de-serialización de la segunda.

¿Existen también estrategias para la futura versión de prueba de mi segunda versión de la clase?

+1

Hacer un programa de conversión que lee objetos del primer tipo, produce objetos del segundo tipo y reemplaza los antiguos por nuevos. Ejecutar ese programa debería llevar mucho tiempo, si se trata de cientos, no millones de registros. – dasblinkenlight

+2

Hay un artículo dedicado de MSDN al respecto. Mejor comenzar allí: http://msdn.microsoft.com/en-US/library/ms229752%28v=vs.90%29.aspx –

Respuesta

4

Sin la preparación de su parte, es posible que tenga que recurrir a un truco: cuando su public myClass deserialización constructor obtiene el valor de bool d, incluya el código en try/catch, y establecer d a su valor por defecto cuando se captura una excepción .

En el futuro, añadir un valor int"__ver" (o cualquier otro nombre que no chocan con los argumentos que se pasan a info.AddValue), y ponerlo en una constante que se mantiene en su clase para indicar cambios compatibles e incompatibles en serialización:

public class myClass : ISerializable { 
    private const int __ver = 4; 
    public int a; 
    public string b; 
    public int c; 
    public bool d; 

    public void GetObjectData(SerializationInfo info, 
          StreamingContext context) { 
     info.AddValue("__ver", ver); 
     info.AddValue("a", a); 
     // and so on 
    } 

    public myClass(SerializationInfo info, 
       StreamingContext context) { 
     switch(info.GetInt32("__ver")) { 
      case 3: 
       // Deserialize prior version 
      break; 
      case 4: 
       // Deserialize current version 
      break; 
     } 
    } 
} 
+0

El único problema es que todas las instancias actuales en la base de datos no tienen el campo __ver en ellas , por lo que no podrá actualizar esta implementación. –

+0

'SerializationInfo' no tiene algo como' ContainsKey() '? Creo que sería muy útil aquí. – svick

+0

Creo que podrías usar 'MemberCount' o' GetEnumerator() 'para evitar el' try'/'catch'. – svick

2

clases serializables son grandes para pasarlos alrededor a través de la misma versión de software, sino que golpean este problema rápidamente cuando se la usa para la persistencia. Si va a almacenar objetos como BLOBs, entonces quizás use algo como protobuf-net que permite versiones de serialización al permitir campos opcionales.

Dada su situación actual todo lo que puede hacer para conseguir que funcione llevaron inmediatamente se puso un intento de captura en torno a los nuevos campos, y luego por defecto si no están allí:

protected myClass(SerializationInfo info, StreamingContext context) 
{ 
    c = info.GetInt32("Value_C"); 
    try 
    { 
     b = info.GetBoolean("Value_B"); 
    } 
    catch (SerializationException) 
    { 
     b = true; 
    } 
} 
Cuestiones relacionadas