2017-07-26 30 views
1

我發現自己在這一點上有點失落。如果這只是一個類結構不匹配JSON錯誤,我真的不能看到錯誤。但我懷疑它,因爲它與我用來創建JSON的類結構完全相同。Json.Net具有ObservableCollection和INotifyPropertyChange的類層次結構被序列化,但未被反序列化

如果任何人都能指引我走向正確的方向,

我已經創建了一個dotnetfiddle,以避免用巨大的代碼片斷抓住問題。這裏是鏈接:Fiddle

我生成的JSON與控制檯應用程序獲取數據庫架構上的信息。我使用一個通用項目,將其中定義的所有實體加載到內存中,然後從該結構生成JSON。然後,我在另一個應用程序中使用相同的項目與另一個應用程序中的相同實體比較另一個DB模式與JSON日誌。該應用程序無法反序列化JSON。試圖提供一個簡單的例子與一個單一的類,你可以看到在小提琴......不反序列化。 這是我的理解,ObservableCollections實際上應該序列化和反序列化沒有問題,並且INotifyPropertyChange不應該導致問題(只要你不試圖用空引用觸發事件)。所以......任何人都知道這裏發生了什麼?

編輯:忘了提。注意只有基類型字符串得到反序列化......所以它運行一些反序列化,而不是像ObservableCollection或用戶類這樣的類。也許這有助於以某種方式查明問題。

EDIT2:添加了微量的作家和JSON.Net跟蹤被檢測爲對象的權利類型,所以我猜這個問題是轉換類型或初始化一些類型

回答

1

的問題是在Json.Net中的設置如何與默認的ObjectCreationHandling設置結合使用。請允許我解釋:

默認情況下,如果引用屬性在反序列化過程中有一個存在的(非null)值,Json.Net會嘗試重用現有實例並填充它,而不是創建新實例。爲了找出屬性是否有值,Json.Net調用getter。在你的情況下,當支持字段爲空getter方法會返回一個新的實例,但是,關鍵的是,它不支持字段設置爲新的實例:

get { return _header ?? new StoredProcedureDataHeader(); } 

Json.Net然後填充新的實例。由於後臺字段從未設置爲新實例,因此該實例最終會被丟棄。 Json.Net永遠不會調用你的setter,因爲它假定你的對象已經有了對新實例的引用,因爲它從getter獲得了這個實例。然後,當你在反序列化之後下一次調用getter時,你將得到一個新的空實例,而不是你期望的。

有兩種方法來解決這個問題:

  1. 改變你的干將設置支持字段只要創建一個新的實例,例如:

    get 
    { 
        if (_header == null) 
        { 
         _header = new StoredProcedureDataHeader(); 
        } 
        return _header; 
    } 
    

OR

  • 更改ObjectCreationHandling設置爲Replace強制Json。Net在反序列化時始終創建新實例。然後Json.Net會調用setter和不消氣,我認爲這是你想要的。

    var settings = new JsonSerializerSettings 
    { 
        ObjectCreationHandling = ObjectCreationHandling.Replace 
    }; 
    
    var data = JsonConvert.DeserializeObject<StoredProcedureData>(json, settings); 
    
  • 在你的情況,我真的建議您應用修復。如果不解決您的getter方法(方案1),你可以在你的代碼運行到類似的問題在其他地方。例如,你可能有這樣的事情:

    var data = new StoredProcedureData(); 
    data.Header.SPName = "foo"; 
    if (data.Header.SPName == "foo") 
    { 
        Console.WriteLine("foo"); 
    } 
    else 
    { 
        Console.WriteLine("oops"); 
    } 
    

    猜猜哪個值會被打印?

    和期權2將防止可能意外的結果,如果你碰巧有初始化集合的地方有值的默認設置。舉例來說,如果你有這樣的事情:

    public StoredProcedureData() 
    { 
        _funcRef = new ObservableCollection<string>(); 
        _funcRef.Add("Initialize"); 
    } 
    

    然後當你反序列化,你會得到從JSON,這可能不是你想要的默認值值。設置ObjectCreationHandlingReplace將確保你將最終只是這是從JSON反序列化的值。

    +0

    謝謝你的解釋。我確實應用了這兩個修補程序。我太專注於JSON格式,我從來沒有看過那個孤兒比如我創建。有點尷尬。 –

    +0

    不用擔心。很高興我能夠提供幫助。 –