在Json.net中获取错误“无法在Newtonsoft.Json.Linq.JProperty中添加或删除项”

时间:2014-02-20 05:14:18

标签: c# json serialization json.net

所以我试图通过将json对象作为JObject读取,删除一些字段,然后使用Json.Net将其再次反序列化到我的目标对象来控制反序列化。问题是,每当我尝试删除字段时,都会收到错误:

  

“Newtonsoft.Json.JsonException”类型的未处理异常   发生在Newtonsoft.Json.dll

     

其他信息:无法添加或删除项目   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反序列化为特定类型,但仍然忽略其他字段,那将是一个很好的选择。

2 个答案:

答案 0 :(得分:61)

假设ValuesList<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或从JToken移除子JArray是合法的。但是,您无法从JProperty中删除该值。 JProperty必须始终只有一个值。

当您要求token["_id"]时,您会收到名为JProperty的{​​{1}}的,而不是_id本身。因此,如果您尝试在该值上调用JProperty,则会收到错误消息。为了使其按照您的方式工作,您需要使用Remove(),如下所示:

Parent

这表示“查找名称为if (inner["_id"] != null) inner["_id"].Parent.Remove(); 的属性并为其提供值。如果存在,请获取该值的父级(属性),并将其从父级(包含_id中删除)“。

更直接的方法是使用JObject方法直接访问该属性。但是,此方法仅适用于Property(),而不是JObject,因此您需要将JToken的声明更改为inner或投射它:

JObject

最后,如评论中所述,如果您使用的是C#6或更高版本,则可以使用空条件运算符稍微缩短代码:

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

答案 1 :(得分:-3)

根据Brian的Brillian回答,你可以在你的情况下做到这一点:

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