关于c#:JArray.Remove(JToken)不会删除

 2021-04-27 

JArray.Remove(JToken) does not delete

我有一个带有JSON的JObject,如下所示:

1
{"name" :"user1","groups" : ["group 1","group2"]}

我想按名称删除一个组。所以我有这样的代码:

1
2
3
4
5
6
JObject userJson = JObject.Parse(user);

JArray groups = userJson["groups"] as JArray;
JToken group = new JValue (groupName);

groups.Remove(group);

但是方法JArray.remove(Jtoken item)返回false(这意味着它不能被删除)。这里的信息:

https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JArray_Remove.htm

因此尝试设置像JToken group = new JValue (groupName); JToken group = new JValue (groupName); as JTokenJValue group = new JValue (groupName);这样的参数,但是它不起作用:S

这个人很好地解释了JToken层次结构,但是我不知道我做错了什么。

https://stackoverflow.com/a/38560188/8849646


基本问题是JToken层次结构是双连接图。也就是说,每个令牌都知道其Parent,每个父节点都知道其Children。实际上,如果将已经具有父代的令牌添加到父代,它将被克隆,如此处所述。

因此,由于每个令牌都知道其父级,因此当您尝试从父级中删除令牌时,Json.NET可能会执行以下两项操作之一:

  • 如果子对象实际上属于父对象,则可能会将其从父对象中移除(使用引用等式),或者
  • 如果该子级具有作为父级某个子级的保存值,则可能会将其从父级中删除。
  • 事实上,Json.NET选择了前一个选项。 Jarray.Remove(JToken item)调用JContainer.RemoveItem(),后者调用JArray.IndexOfItem()确定要删除的项目的索引。反过来,此方法使用引用相等:

    1
    2
    3
    4
    internal override int IndexOfItem(JToken item)
    {
        return _values.IndexOfReference(item);
    }

    由于您的JToken group = new JValue (groupName)不属于JArray groups,因此不会将其删除。

    那么,按值删除JSON数组项的选项是什么?您可以:

    • 使用LINQ搜索:

      1
      groups.Where(i => i.Type == JTokenType.String && (string)i == groupName).ToList().ForEach(i => i.Remove());
    • 使用JTokenEqualityComparer进行搜索,该搜索可用于搜索复杂对象以及原始值:

      1
      2
      var comparer = new JTokenEqualityComparer();
      groups.Where(i => comparer.Equals(i, group)).ToList().ForEach(i => i.Remove());
    • 使用SelectTokens()搜索:

      1
      userJson.SelectTokens(string.Format("groups[?(@ == '{0}')]", groupName)).ToList().ForEach(i => i.Remove());

      SelectTokens()支持JSONPath查询语法,该语法使您可以在数组中搜索匹配项。

    最后,关于RemoveItem()文档的注释。它指出(添加斜体):

    JArray.Remove Method (JToken)

    Removes the first occurrence of a specific object from the JArray.

    由于我们已经看到具有父级的令牌在添加到父级时会被克隆,因此在给定的父级中似乎永远都不会出现任何令牌。然而,文档似乎暗示着其他情况。我可能会猜测,这个特定的文档句子已经过时,并且可以追溯到Json.NET的早期版本,在该版本中,相同的令牌可能在父级中多次出现。


    1
    2
    3
    4
    5
    6
    7
    //Removing obj from oldArray
    private static JArray RemoveValue(JArray oldArray, dynamic obj)
    {
        List<string> temp2 = oldArray.ToObject<List<string>>();
        temp2.Remove(obj);
        return JArray.FromObject(temp2);
    }