Field Initializer in C # Class non eseguito quando deserializza

Ho una class che definisce un campo protetto. Il campo protetto ha un inizializzatore di campo.

Quando deserializzo la class concreta, l’inizializzatore di campo non viene eseguito. Perché? Qual è il miglior schema per risolvere il problema? Se sposto l’inizializzazione in un costruttore, anche il costruttore non viene invocato.

[DataContract] public class MyConcrete { // FIELD INITIALIZER DOES NOT RUN WHEN COMMENTED IN: protected readonly Dictionary myDict;// = new Dictionary(); public MyConcrete() { myDict = new Dictionary(); } private bool MyMethod(int key) { return myDict.ContainsKey(key); } private int myProp; [DataMember] public int MyProp { get { return myProp; } set { bool b = MyMethod(value); myProp = value; } // Call MyMethod to provoke error } } 

GERARCHIA DI CLASSE ORIGINALE

 [DataContract] public abstract class MyAbstract { // THIS INITIALIZER IS NOT RUN WHILE DESERIALIZING: protected readonly Dictionary myDict = new Dictionary(); private bool MyMethod(int key) { return myDict.ContainsKey(key); } private int myProp; [DataMember] public int MyProp { get { return myProp; } set { bool b = MyMethod(value); myProp = value; } // Call MyMethod to provoke error } } [DataContract] public class MyConcrete : MyAbstract { } class Program { static void Main(string[] args) { string tempfn = Path.GetTempFileName(); MyConcrete concrete = new MyConcrete() { MyProp = 42 }; string data = concrete.SerializeToString(); MyConcrete rehydrated = SerializationHelper.DeserializeFromString(data); } } 

METODI DI SUPPORTO

 static public string SerializeToString(this T obj) { return SerializationHelper.SerializeToString(obj); } static public string SerializeToString(T obj) { DataContractSerializer s = new DataContractSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream()) { s.WriteObject(ms, obj); ms.Position = 0; using (StreamReader sr = new StreamReader(ms)) { string serialized = sr.ReadToEnd(); return serialized; } } } static public T DeserializeFromString(string serializedDataAsString) { DataContractSerializer s = new DataContractSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(serializedDataAsString))) { object s2 = s.ReadObject(ms); return (T)s2; } } 

Alla deserializzazione non vengono chiamati né i costruttori né gli inizializzatori di campo e viene invece utilizzato un object non inizializzato “vuoto”.

Per risolverlo è ansible utilizzare gli attributi OnDeserializing o OnDerserialized per fare in modo che il deserializzatore chiami una funzione con la seguente firma:

 void OnDeserializing(System.Runtime.Serialization.StreamingContext c); 

In questa funzione è ansible inizializzare ciò che è mancato nel processo di deserializzazione.

In termini di convenzione, tendo ad avere il mio costruttore per chiamare un metodo OnCreated() e poi anche il metodo deserializzazione chiama la stessa cosa. È quindi ansible gestire tutte le inizializzazioni del campo e assicurarsi che sia stato triggersto prima della deserializzazione.

 [DataContract] public abstract class MyAbstract { protected readonly Dictionary myDict; protected MyAbstract() { OnCreated(); } private void OnCreated() { myDict = new Dictionary(); } [OnDeserializing] private void OnDeserializing(StreamingContext c) { OnCreated(); } private bool MyMethod(int key) { return myDict.ContainsKey(key); } private int myProp; [DataMember] public int MyProp { get { return myProp; } set { bool b = MyMethod(value); myProp = value; } } } 

Un altro approccio è quello di accedere al tuo campo attraverso una proprietà protetta (nel tuo esempio) e inizializzare il campo usando l’operatore null-coalescing ( ?? )

 protected Dictionary myDict = new Dictionary(); protected Dictionary MyDict { get { return myDict ?? (myDict = new Dictionary()); } } 

Gli svantaggi sono che perdi i vantaggi di readonly e devi assicurarti di accedere al valore solo tramite la proprietà.