2012-04-19 8 views
6

Ho questa classeStrategia per deserializzazione una classe che è cambiato in .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 
     } 
} 

Ho centinaia di questi oggetti nel mio database. Ora sono pronto a pubblicare una nuova versione della mia app in cui la classe si è trasformato per

[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 
     } 
} 

Come ci si deserializzare un oggetto serializzato in base alla prima versione con il costruttore de-serializzazione del secondo.

Esistono anche strategie per la versione futura che verifica la mia seconda versione della classe?

+1

Fai un programma di conversione che legge oggetti del primo tipo, produce oggetti del secondo tipo e sostituisce i vecchi con nuovi. L'esecuzione di quel programma dovrebbe richiedere molto tempo, se si parla di centinaia, non di milioni di record. – dasblinkenlight

+2

C'è un articolo MSDN dedicato a riguardo. Meglio iniziare da lì: http://msdn.microsoft.com/en-US/library/ms229752%28v=vs.90%29.aspx –

risposta

4

Senza una preparazione da parte vostra, potrebbe essere necessario ricorrere a un hack: quando il costruttore di deserializzazione public myClass ottiene il valore di bool d, racchiudere il codice in try/catch, e impostare d al suo valore di default quando si cattura un'eccezione .

In futuro, aggiungere un int valore "__ver" (o qualsiasi altro nome che non si scontrano con argomenti che si passa a info.AddValue), e impostarlo su una costante che si mantiene nella tua classe per indicare le modifiche compatibili e incompatibili serializzazione:

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

Unico problema è che tutte le istanze correnti nel database non hanno il campo __ver su di esse , quindi non sarai in grado di adattare questa implementazione. –

+0

'SerializationInfo' non ha qualcosa come' ContainsKey() '? Penso che sarebbe molto utile qui. – svick

+0

Penso che potresti usare 'MemberCount' o' GetEnumerator() 'per evitare' try'/'catch'. – svick

2

classi Serializable sono grandi per passare in giro attraverso la stessa versione del software, ma ha colpito questo problema in fretta quando lo si utilizza per la persistenza. Se hai intenzione di archiviare oggetti come BLOBs, allora forse usi qualcosa come protobuf-net che consente il controllo della serializzazione consentendo campi facoltativi.

Data la tua attuale situazione tutto quello che puoi fare per farlo funzionare imediatly è mettere un tentativo di cattura in tutto i nuovi campi, e poi li default se non sono lì:

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