反序列化时,C#类中的字段初始化程序不运行

我有一个定义受保护字段的类。 受保护的字段具有字段初始值设定项。

当我反序列化具体类时,不会运行字段初始值设定项。 为什么? 解决问题的最佳模式是什么? 如果我将初始化移动到构造函数中,也不会调用构造函数。

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

原始阶层等级

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

支持方法

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

在反序列化时, 既不调用构造函数也不调用字段初始值设定项,而是使用“空白”未初始化对象。

要解决它,您可以使用OnDeserializingOnDerserialized属性让反序列化器调用具有以下签名的函数:

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

在该函数中,您可以初始化反序列化过程中遗漏的任何内容。

在约定方面,我倾向于让我的构造函数调用一个方法OnCreated() ,然后还有deserializating方法调用相同的东西。 然后,您可以在那里处理所有字段初始化,并确保在反序列化之前触发它。

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

另一种方法是通过受保护的(在您的示例中)属性访问您的字段,并使用null-coalescing( ?? )运算符初始化该字段

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

缺点是你失去了readonly的好处,并且需要确保你只通过属性访问该值。