2014-02-20 25 views
15

所以我試圖通過讀取json對象作爲JObject來控制反序列化,刪除一些字段,然後反序列化它再次使用Json.Net對我的目標對象。問題是,任何時候我嘗試刪除字段,我得到的錯誤:在Json.net中得到錯誤「無法從Newtonsoft.Json.Linq.JProperty中添加或刪除項目」

An unhandled exception of type 'Newtonsoft.Json.JsonException' occurred in Newtonsoft.Json.dll

Additional information: Cannot add or remove items from Newtonsoft.Json.Linq.JProperty.

這裏是我(簡化,但仍導致錯誤)代碼:

JToken token = (JToken)JsonConvert.DeserializeObject(File.ReadAllText(fileName)); 

foreach (JToken inner in token["docs"]) 
{ 
    if (inner["_id"] != null) 
     inner["_id"].Remove(); 

    MyObject read = new MyObject(); 
    JsonConvert.PopulateObject(inner.ToString(), read); 
    Values.Add((MyObject)JsonConvert.DeserializeObject(inner.ToString(), typeof(MyObject))); 
} 

的JSON是一個很大文件,其中的文檔數組包含如下許多元素(再次簡化爲清楚起見):

{ 
    "docs": [ 
     { 
      "Time": "None", 
      "Level": 1, 
      "_id": "10208"    
     }, 
     { 
      "Time": "None", 
      "Level": 1, 
      "_id": "10209" 
     } 
    ] 
} 

或者,如果有更好的方法來反序列化JSON特定類型,但還是忽略了其他字段,塔噸將是一個很好的選擇。

+0

請張貼您的JSON –

+0

我不確定它是否相關,因爲我們知道inner [「id」]不是null,但我已經把它放在了問題上。 – Miguel

回答

42

假設ValuesList<MyObject>和你MyObject類看起來是這樣的:

string json = File.ReadAllText(fileName); 
Values = JToken.Parse(json)["docs"].ToObject<List<MyObject>>(); 

這樣做是因爲:

class MyObject 
{ 
    public string Time { get; set; } 
    public int Level { get; set; } 
} 

你可以用下面來得到你想要的結果替換所有的代碼Json.Net默認會忽略缺少的屬性。由於MyObject類不包含要反序列化的_id屬性,因此您無需跳過試圖從JSON中將其刪除的箍環。爲什麼Remove()沒有工作

JToken.Remove()

說明刪除從其父JToken。從其父母JObject中刪除JProperty或從JArray中刪除子女JToken是合法的。但是,您無法從JProperty中刪除該值。 A JProperty必須始終只有一個值。

當你問token["_id"]你回來了JProperty稱爲_id,而不是JProperty本身的價值。因此,如果您嘗試致電Remove()那麼您將收到錯誤。爲了使它工作,你正在做的方式,你需要這樣做:

if (inner["_id"] != null) 
    inner["_id"].Parent.Remove(); 

這是說「找他的名字是_id,給我的價值的財產,如果它存在,獲取價值的父(。該財產),並將其從其父母(包含JObject)中刪除。「

另一種方式來做到這一點是可能更清楚一點是這樣說:

JProperty id = inner.Children<JProperty>().FirstOrDefault(p => p.Name == "_id"); 
if (id != null) 
    id.Remove(); 
+0

謝謝,知道Json.net忽略額外的屬性是非常有用的。這就是說,我仍然很想知道爲什麼我無法刪除()字段。 – Miguel

+3

我已更新我的答案,添加您要求的解釋。 –

+1

非常感謝!這正是我期待的解釋! – Miguel

-2

基於布萊恩BRILLIAN答案,你可以做簡單,就是在你的情況:

var inner_id = inner["_id"] as JProperty; 
if (inner_id != null) 
    inner_id.Remove(); 
+0

對不起,這不起作用。正如我在我的回答中所述,使用索引器語法將爲您提供'JProperty'的值,而不是'JProperty'本身的值。該值永遠不會是'JProperty',因爲JProperties不能直接包含其他'JProperties'。因此,當您嘗試將'inner [「_ id」]'表達式轉換爲'JProperty'時,它將始終爲'null',因此'Remove()'永遠不會被調用。看看你自己:https://dotnetfiddle.net/EkTU4o –

+0

啊......這很混亂,但我現在明白了。突然我的項目中的代碼按預期工作!儘管我的答案是錯誤的,但我仍然認爲它不能做到這一點...... – awe

相關問題