這幾天對動態實體做了一些修改,然後同事們一運行就出錯了,仔細調試後發現是在還原序列化時,我寫了一個回調,然而發生回調時,對象沒有完全初始化完畢。具體是這樣的:
我有個類:DependencyMetadataBase,包含一個方法: [OnDeserialized()]
private void OnDeserialized(StreamingContext context) {
this.OnDeserialization(null);
}
而且,這個類的衍生類別包含了一個內部變數:private DependencyPropertyData _data;
很不幸,這個還原序列化時的回調需要使用_data變數,跟蹤發現,當回調發生時,_data不是null,但_data內部的變數中,實值型別(包括string)都已經填充,但是參考型別(Class)的都是null,導致了我的回調發生錯誤。
查看MSDN,得到以下文字:
對象將被徹底重新構造,並且在還原序列化期間調用方法可能會產生不良的副作用,因為被調用的方法可能引用在進行此調用時尚未被還原序列化的對象引用。如果還原序列化的類實現,則在整個對象圖已被還原序列化後將自動調用 方法。此時,所有引用的子物件均已被完全還原。雜湊表就是在不使用事件接聽程式的情況下很難還原序列化的類的典型樣本。在還原序列化期間檢索鍵/值對十分容易,但將這些對象添加回雜湊表可能會造成一些問題,因為不能保證從雜湊表派生的類已被還原序列化。因此,不建議在此階段對雜湊表調用方法。
所以,我使用IDeserializationCallback實現了回調功能。事實上,我以前另外一個類就使用了IDeserializationCallback這個方法,但為什麼後來這個類又不用呢?當時遇到一個問題,假設A實現了IDeserializationCallback,而B也實現了,很遺憾,當A引用了B並還原序列化時,並不能保證B先被調用IDeserializationCallback方法,所以當A的IDeserializationCallback調用了B的資料時,很可能B沒有調用IDeserializationCallback,造成程式的錯誤。
所以在當時,我使用了最終的解決方案是都實現Callback模式,但是在A調用B前,先檢查B是否已經調用過Callback,如果沒有,提前調用。