基本问题是JToken
层次结构是双连通图。也就是说,每个令牌都知道它Parent
,每个父代都知道它Children
。实际上,如果您将已经有父代的令牌添加到父代,它会被克隆,如此处所述。
因此,由于每个令牌都知道其父级,因此当您尝试从父级移除令牌时,Json.NET 可能会执行以下两种操作之一:
- 如果孩子实际上属于父母(使用引用相等),它可能会从父母中删除孩子,或者
- 如果子项具有作为父项的某个子项的保存值,它可能会从父项中删除子项。
而且,事实上,Json.NET 选择了前一个选项。 Jarray.Remove(JToken item)
调用JContainer.RemoveItem()
which 调用JArray.IndexOfItem()
以确定要删除的项目的索引。反过来,此方法使用引用相等:
internal override int IndexOfItem(JToken item)
{
return _values.IndexOfReference(item);
}
由于您的JToken group = new JValue (groupName)
不属于JArray groups
,因此不会将其删除。
那么,您有哪些按值删除 JSON 数组项的选项?你可以:
使用 LINQ 搜索:
groups.Where(i => i.Type == JTokenType.String && (string)i == groupName).ToList().ForEach(i => i.Remove());
Search using JTokenEqualityComparer
,可用于搜索复杂对象以及原始值:
var comparer = new JTokenEqualityComparer();
groups.Where(i => comparer.Equals(i, group)).ToList().ForEach(i => i.Remove());
使用搜索SelectTokens()
:
userJson.SelectTokens(string.Format("groups[?(@ == '{0}')]", groupName)).ToList().ForEach(i => i.Remove());
SelectTokens()
支持JSONPath 查询语法,可以通过数组搜索匹配项。
最后,关于. RemoveItem()
它指出(添加斜体):
JArray.Remove Method (JToken)
从 JArray 中删除特定对象的第一个匹配项。
由于我们已经看到具有父代的令牌在添加到父代时会被克隆,因此在给定的父代中似乎只能出现一次任何令牌。然而,文档似乎另有暗示;我会大胆猜测这个特定的文档语句已经过时,并且可以追溯到一些更早的 Json.NET 版本,其中相同的标记可能多次出现在父级中。