簡體   English   中英

在Json.net中收到錯誤“無法從Newtonsoft.Json.Linq.JProperty添加或刪除項目”

[英]Getting the error “Cannot add or remove items from Newtonsoft.Json.Linq.JProperty” in Json.net

因此,我試圖通過將json對象讀取為JObject,刪除一些字段,然后使用Json.Net將其反序列化為我的目標對象,來控制反序列 問題是,每當我嘗試刪除字段時,都會收到錯誤消息:

Newtonsoft.Json.dll中發生了類型為'Newtonsoft.Json.JsonException'的未處理異常

附加信息:無法從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數組包含許多元素,如下所示(為簡化起見,再次簡化):

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

另外,如果有更好的方法將JSON反序列化為特定類型,但仍然忽略其他字段,那將是一個很好的選擇。

假定Values是一個List<MyObject>並且您的MyObject類如下所示:

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

您可以將所有代碼替換為以下代碼,以獲得所需的結果:

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

之所以可行,是因為Json.Net默認會忽略缺少的屬性。 由於MyObject類不包含要反序列化的_id屬性,因此您無需跳過試圖將其從JSON中刪除的箍。

解釋為什么Remove()不起作用

JToken.Remove()從其父級移除JToken 它是合法的刪除JProperty從其父JObject ,或刪除一個孩子JTokenJArray 但是,您不能從JProperty刪除該值。 JProperty必須始終僅具有一個值。

當您請求token["_id"]您將獲得稱為_idJProperty ,而不是JProperty本身。 因此,如果您嘗試對該值調用Remove() ,則會收到錯誤消息。 要使其按照您的方式工作,您需要像這樣使用Parent

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

這說:“查找名稱為_id的屬性,並給我值。如果存在,請獲取該值的父級(屬性),並將其從其父級(包含JObject )中JObject 。”

一種更直接的方法是使用Property()方法直接訪問該屬性。 但是,此方法僅在JObjectJObject ,而在JObject不可JToken ,因此您需要將inner的聲明更改為JObject或將其JObject為:

foreach (JObject inner in token["docs"].Children<JObject>())
{
    JProperty idProp = inner.Property("_id");
    if (idProp != null)
        idProp.Remove();
    ...
}

最后,如注釋中所述,如果您使用的是C#6或更高版本,則可以使用null條件運算符將代碼縮短一些:

    inner.Property("_id")?.Remove();

根據Brian的brillian回答,您可以根據自己的情況簡單地執行以下操作:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM