所以我试图通过将json对象作为JObject读取,删除一些字段,然后使用Json.Net将其反序列化为我的目标对象来控制反序列化。问题是,每当我尝试删除字段时,都会收到错误消息:
Newtonsoft.Json.dll中发生了类型为’Newtonsoft.Json.JsonException’的未处理异常 附加信息:无法从Newtonsoft.Json.Linq.JProperty添加或删除项目。
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是a List<MyObject>,您的MyObject课程如下所示:
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中删除的箍。
_id
解释为什么Remove()不起作用
Remove()
JToken.Remove()``JToken从其父级中删除一个。JProperty从父母JObject中删除子女或JToken从子女中删除子女是合法的JArray。但是,您无法从中删除值JProperty。一个JProperty必须始终只有一个值。
JToken.Remove()``JToken
JProperty
JObject
JToken
JArray
当您要求时,token["_id"]可以获取被调用的 值 ,而不是其本身。因此,如果尝试调用该值,将会得到一个错误。要使其按照您的方式工作,您需要使用以下代码:JProperty``_id``JProperty``Remove()``Parent
token["_id"]
JProperty``_id``JProperty``Remove()``Parent
if (inner["_id"] != null) inner["_id"].Parent.Remove();
这样说:“查找名称为“的属性_id并给我值。如果存在,请获取该值的父级(属性),然后从其父级(包含JObject)中删除它”。
一种更直接的方法是使用该Property()方法直接访问属性。但是,此方法仅在上JObject不可用JToken,因此您需要将的声明更改inner为a JObject或将其强制转换为:
Property()
inner
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();