收到错误“无法从 Newtonsoft.Json.Linq.JProperty 添加或删除项目"在 Json.

Getting the error quot;Cannot add or remove items from Newtonsoft.Json.Linq.JPropertyquot; in Json.net(收到错误“无法从 Newtonsoft.Json.Linq.JProperty 添加或删除项目在 Json.net 中)
本文介绍了收到错误“无法从 Newtonsoft.Json.Linq.JProperty 添加或删除项目"在 Json.net 中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

所以我试图通过将 json 对象作为 JObject 读取,删除一些字段,然后使用 Json.Net.问题是,每当我尝试删除字段时,都会收到错误消息:

So I'm trying to control deserialization by reading a json object as a JObject, deleting some fields, and then deserializing it again to my target object using Json.Net. The problem is, any time I try to delete a field, I get the error:

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

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

附加信息:无法添加或删除项目Newtonsoft.Json.Linq.JProperty.

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

这是我的(简化,但仍然导致错误)代码:

Here's my (simplified, but still causing the error) code:

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 数组包含许多元素,如下所示(为清楚起见再次简化):

The json is a very large file where the docs array contains many elements as follows (again simplified for clarity):

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

或者,如果有更好的方法将 JSON 反序列化为特定类型,但仍然忽略其他字段,那将是一个不错的选择.

Alternatively if there's a better way to deserialize JSON to a specific type, but still ignoring additional fields, that would be a fine alternative.

推荐答案

假设 Values 是一个 List 和你的 MyObject 类看起来像这样:

Assuming Values is a List<MyObject> and your MyObject class looks like this:

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

您可以将所有代码替换为以下代码以获得您想要的结果:

you can replace all that code with the following to get the result you want:

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

这是因为 Json.Net 默认会忽略缺失的属性.由于 MyObject 类不包含要反序列化的 _id 属性,因此您无需费力尝试将其从 JSON 中删除.

This works because Json.Net will ignore missing properties by default. Since the MyObject class does not contain an _id property to deserialize into, you don't need to jump through hoops trying to remove it from the JSON.

Remove() 不起作用的原因说明

Explanation of why Remove() didn't work

JToken.Remove() 从其父级中删除 JToken.从其父 JObject 中删除 JProperty 或从 JArray 中删除子 JToken 是合法的.但是,您不能从 JProperty 中删除该值.JProperty 必须始终只有一个值.

JToken.Remove() removes a JToken from its parent. It is legal to remove a JProperty from its parent JObject, or to remove a child JToken from a JArray. However, you cannot remove the value from a JProperty. A JProperty must always have exactly one value.

当您请求 token["_id"] 时,您会返回名为 _idJPropertyvalue>,而不是 JProperty 本身.因此,如果您尝试对该值调用 Remove(),您将收到错误消息.要使其按照您的方式工作,您需要像这样使用 Parent:

When you ask for token["_id"] you get back the value of the JProperty called _id, not the JProperty itself. Therefore you will get an error if you try to call Remove() on that value. To make it work the way you are doing, you'd need to use Parent like this:

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

这表示找到名称为 _id 的属性并给我值.如果存在,获取该值的父级(属性),并将其从其父级(包含 JObject)."

This says "Find the property whose name is _id and give me the value. If it exists, get that value's parent (the property), and remove it from its parent (the containing JObject)."

更直接的方法是使用 Property() 方法直接访问属性.但是,此方法仅适用于 JObject,不适用于 JToken,因此您需要将 inner 的声明更改为 JObject 或强制转换:

A more straightforward way to do it is to use the Property() method to access the property directly. However, this method is only available on JObject, not JToken, so you would either need to change the declaration of inner to a JObject or cast it:

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

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

Lastly, as mentioned in the comments, if you're using C# 6 or later you can shorten the code a bit using the null-conditional operator:

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

这篇关于收到错误“无法从 Newtonsoft.Json.Linq.JProperty 添加或删除项目"在 Json.net 中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

Force JsonConvert.SerializeXmlNode to serialize node value as an Integer or a Boolean(强制 JsonConvert.SerializeXmlNode 将节点值序列化为整数或布尔值)
Using JSON to Serialize/Deserialize TimeSpan(使用 JSON 序列化/反序列化 TimeSpan)
Could not determine JSON object type for type quot;Classquot;(无法确定类型“Class的 JSON 对象类型.)
How to deserialize a JSONP response (preferably with JsonTextReader and not a string)?(如何反序列化 JSONP 响应(最好使用 JsonTextReader 而不是字符串)?)
how to de-serialize JSON data in which Timestamp it-self contains fields?(如何反序列化时间戳本身包含字段的JSON数据?)
JSON.Net custom contract serialization and Collections(JSON.Net 自定义合约序列化和集合)