JArray.Remove(JToken)不会删除

时间:2017-12-15 03:42:57

标签: c# json linq-to-json

我有一个像这样的JSON的JObject:

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

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

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

2 个答案:

答案 0 :(得分:2)

基本问题是JToken层次结构是双重连接图。也就是说,每个令牌都知道它的Parent,并且每个父令知道它的Children。实际上,如果您将已经拥有父级的令牌添加到父级,则会对其进行克隆,如here所述。

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

  1. 如果孩子实际上属于父母(使用参考相等),它可能会从父母中删除孩子,或者
  2. 如果孩子的保存值为父母的子女,则可能会从父母中移除孩子。
  3. 事实上,Json.NET选择了前一个选项。 Jarray.Remove(JToken item)调用JContainer.RemoveItem()调用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());
      
    • 使用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 query syntax,可以通过数组搜索匹配的项目。

    最后,关于RemoveItem() documentation的说明。它声明(斜体添加):

      

    <强> JArray.Remove Method (JToken)

         

    从JArray中删除特定对象的第一个次出现。

    由于我们已经看到在添加到父级时克隆了具有父级的令牌,因此似乎在给定父级中只能出现一次任何令牌。但文件似乎暗示不然;我猜想这个特定的文档句子是过时的,并且可以追溯到早期版本的Json.NET,其中同一个令牌可以多次出现在父级中。

答案 1 :(得分:0)

using System;
using System.Runtime.InteropServices;

namespace question
{
    [StructLayout(LayoutKind.Explicit)]
    public struct Union {
        [FieldOffset(0)]
        Int64 field2;
    }

    class Program
    {
        [DllImport("libcrash.so")]
        static extern Union crash(string s);

        static void Main(string[] args)
        {
            crash("boom !!");
            Console.WriteLine("All Done");
        }
    }
}