JArray.Remove(JToken) does not delete

六月ゝ 毕业季﹏ 提交于 2019-12-06 16:10:11

The basic issue is that the JToken hierarchy is doubly-connected graph. That is, each token knows its Parent and each parent knows its Children. Indeed, if you add a token that already has a parent to a parent, it gets cloned, as explained here.

Thus, since every token knows its parent, when you try to remove a token from a parent, Json.NET might do one of two things:

  1. It might remove the child from the parent if the child actually belongs to the parent (using reference equality), OR
  2. It might remove the child from the parent if the child has the save values as some child of the parent.

And, in fact, Json.NET chooses the former option. Jarray.Remove(JToken item) calls JContainer.RemoveItem() which calls JArray.IndexOfItem() to determine the index of the item to remove. This method, in turn, uses reference equality:

internal override int IndexOfItem(JToken item)
{
    return _values.IndexOfReference(item);
}

Since your JToken group = new JValue (groupName) does not belong to the JArray groups, it is not removed.

So, what are your options to remove a JSON array item by value? You could:

  • Search using LINQ:

    groups.Where(i => i.Type == JTokenType.String && (string)i == groupName).ToList().ForEach(i => i.Remove());
    
  • Search using JTokenEqualityComparer, which can be used to search for complex objects as well as primitive values:

    var comparer = new JTokenEqualityComparer();
    groups.Where(i => comparer.Equals(i, group)).ToList().ForEach(i => i.Remove());
    
  • Search using SelectTokens():

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

    SelectTokens() supports the JSONPath query syntax which enables searching though arrays for matching items.

Finally, a note about the documentation for RemoveItem(). It states (italics added):

JArray.Remove Method (JToken)

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

Since we have seen that a token that has a parent is cloned when added to a parent, it seems there can only ever be one occurrence of any token within a given parent. Yet the documentation seems to imply otherwise; I would hazard a guess that this particular documentation sentence is obsolete and dates from some much earlier version of Json.NET where the same token could appear within a parent multiple times.

//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);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!