3

我只注意到在二進制序列化一個奇怪的現象:當我反序列化的字典在我的課,並嘗試一些立即添加到它,我得到一個錯誤,因爲它不是完全初始化:奇怪的反序列化的錯誤,子對象不能完全反序列化

[Serializable] 
class Foo : ISerializable 
{ 
    public Dictionary<int, string> Dict { get; private set; } 

    public Foo() 
    { 
     Dict = new Dictionary<int, string>(); 
    } 

    public Foo(SerializationInfo info, StreamingContext context) 
    { 
     Dict = (Dictionary<int, string>)info.GetValue("Dict", typeof(Dictionary<int, string>)); 
     Dict.Add(99, "test"); // Error here 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("Dict", Dict); 
    } 

} 

在那裏我將數據添加到字典中的線,我得到一個NullReferenceException,但Dict屬性不爲null:它被實例化,但不初始化(所有的字段都爲0或空)。我懷疑它只是用FormatterServices.GetUninitializedObject創建的,但實際上並沒有反序列化。

據我所知,在這一點上,也許它不是假設被完全初始化。所以我嘗試了另一種方法,通過實現IDeserializationCallback接口。 MSDN說:

將當前接口實現爲對象圖的反序列化完成時調用的方法的支持的一部分。

如果一個對象需要在其子對象執行代碼,它可延緩 這個動作,實現IDeserializationCallback,並執行代碼 只有當它被稱爲回該接口上

所以它似乎正是我所需要的,並且我期望我的字典在被調用時被完全初始化...但我得到同樣的錯誤!

[Serializable] 
class Foo : IDeserializationCallback 
{ 
    public Dictionary<int, string> Dict { get; private set; } 

    public Foo() 
    { 
     Dict = new Dictionary<int, string>(); 
    } 

    public void OnDeserialization(object sender) 
    { 
     Dict.Add(99, "test"); // Error here 
    } 
} 

由於IDeserializationCallback被設計爲在子對象執行代碼,我希望孩子反對在這一點上完全初始化。請注意,如果我在字典上手動調用OnDeserialize,它可以正常工作,但不知何故,我認爲我不應該這麼做...

此行爲是否正常?任何人都可以解釋這裏發生了什麼?

+0

我已經檢查了這一點,和事件'[OnDeserialized]'屬性沒有幫助。此外,我已經檢查.NET的源代碼,並基於他們的一切應該被初始化,當任一的'[OnDeserialized]'或'IDeserializationCallback.OnDeserialization'稱爲 –

+0

OnDeserialization當整個對象圖反序列化被調用。我懷疑真正的問題是位於序列化代碼中。從這裏看不到它。 –

回答

0

您需要實例化詞典<>在OnDeserialization處理

public void OnDeserialization(object sender) 
{ 
    Dict = new Dictionary<int, string>(); 
    Dict.Add(99, "test"); // Error here 
} 
+0

如果我這樣做,它不會是我已經序列化的字典...無論如何,我認爲你誤解了我的問題:我不問如何解決問題,我已經有解決方法。我的問題是關於它爲什麼表現如此,因爲文檔提示了不同的行爲。 –

1

如果添加Dict.OnDeserialization(sender)到您的反序列化處理,然後一切都變得很好。

所以,這個工程:

[Serializable] 
    class Foo : IDeserializationCallback 
    { 
     public Dictionary<int, string> Dict { get; private set; } 

     public Foo() 
     { 
      Dict = new Dictionary<int, string>(); 
     } 

     public void OnDeserialization(object sender) 
     { 
      // The dictionary is initialized with values in next line 
      Dict.OnDeserialization(sender); 
      Dict.Add(99, "test"); 
     } 
    } 
+0

我意識到這一點,我在我的問題中提到它... –

+0

從源代碼中,它看起來像字典後處理其內部只有通過OnDeserialization反序列化整個對象圖。這個鉤子在對象之間沒有確定性地被調用,所以如果你的Foo需要調用字典'OnDeserializing',它必須手動調用字典的方法。根據源代碼評論,它可能被多次調用而沒有問題。 (超出第一個的調用導致無操作。)請注意,出於同樣的原因,您應該檢查Foo的OnDeserialization方法以防止多個調用。 –