2012-02-17 11 views
11

Ho bisogno di inizializzare il campo privato readonly dopo la deserializzazione. Ho folowing DataContract:Inizializza campi privati ​​readonly dopo la deserializzazione

[DataContract] 
public class Item 
{ 
    public Item() 
    { 
     // Constructor not called at Deserialization 
     // because of FormatterServices.GetUninitializedObject is used 
     // so field will not be initialized by constructor at Deserialization 
     _privateReadonlyField = new object(); 
    } 

    // Initialization will not be called at Deserialization (same reason as for constructor) 
    private readonly object _privateReadonlyField = new object(); 

    [DataMember] 
    public string SomeSerializableProperty { get; set; } 

    [OnDeserializing] 
    public void OnDeserializing(StreamingContext context) 
    { 
     // With this line code even not compiles, since readonly fields can be initialized only in constructor 
     _privateReadonlyField = new object(); 
    } 
} 

Tutto quello che mi serve, che dopo la deserializzazione _privateReadonlyField non è nullo.

Qualche suggerimento su questo - è possibile a tutti? Oppure ho bisogno di rimuovere la chiave "readonly", che non è una buona opzione.

+0

Quale metodo di serializzazione stai usando? La costruzione degli oggetti differisce per diversi metodi. –

+0

Cosa c'è di sbagliato nel contrassegnare il tuo '_privateReadonlyField' a' [DataMember] '? Il serializzatore del contratto di dati si prenderà cura di esso senza problemi. – dasblinkenlight

+0

Joachim Isaksson: sto utilizzando DataContractJsonSerializer ma in realtà non importa: tutti i serializzatori utilizzano FormatterServices.GetUninitializedObject durante la deserializzazione. – Andris

risposta

7

Qualsiasi campo dichiarato come private readonly può essere istanziato nella stessa riga in cui è stato dichiarato o all'interno di un costruttore. Una volta fatto, non può essere modificato.

Da MSDN:

La parola chiave in sola lettura è un modificatore che è possibile utilizzare sui campi. Quando una dichiarazione di campo include un modificatore di sola lettura, le assegnazioni ai campi introdotti dalla dichiarazione possono avvenire solo come parte della dichiarazione o in un costruttore della stessa classe.

Ciò significa che sarà necessario rimuovere la parola chiave readonly per farlo funzionare.

+0

Grazie, Huske. Sfortunatamente tu mi hai approvato, ho sperato che esistesse un modo per risolvere questo problema. – Andris

8

La serializzazione è in grado di leggere i valori per i campi di sola lettura poiché utilizza la riflessione, che ignora le regole di accessibilità. Si può sostenere che la segue è, quindi, giustificata come parte del processo di serializzazione, anche se mi sento di raccomandare vivamente contro di essa in quasi ogni altra circostanza:

private readonly Doodad _oldField; 

[OptionalField(VersionAdded = 2)] 
private readonly Widget _newField; 

[OnDeserialized] 
private void OnDeserialized(StreamingContext context) 
{ 
    if (_oldField != null && _newField == null) 
    { 
     var field = GetType().GetField("_newField", 
      System.Reflection.BindingFlags.Instance | 
      System.Reflection.BindingFlags.DeclaredOnly | 
      System.Reflection.BindingFlags.NonPublic); 
     field.SetValue(this, new Widget(_oldField)); 
    } 
} 
+1

Grazie per la risposta. Ho davvero dimenticato la riflessione, quando ho posto la domanda. – Andris

+0

Che effetto ha l'attributo '[OptionalField]' su questa soluzione? 'OnDeserialized' funziona ancora senza di esso? –

+0

Se non ricordo male, omettere causerà la deserializzazione per generare un'eccezione quando si legge un input che non contiene quel campo. –

Problemi correlati