我可以依靠通过JsonSerializer读取的节点顺序吗?

时间:2018-09-18 07:23:36

标签: json json.net jsonserializer

我在这里读过 Is the order of elements in a JSON list preserved?

Json中的顺序很重要

我也在这里读过 Does List<T> guarantee insertion order? 保证在C#通用列表中的插入顺序

我是否可以假设当我使用newtonsoft JsonSerializer来读取此Json

 "answers": [
            {
                "choice": "36"
            },
            {
                "choice": "50"
            }
        ]

在属性为“答案”的对象中,该对象的类型为GenericList,答案[0]始终返回36,答案[1]始终返回50?

或者JsonSerializer可能会在周围乱洗数据吗?

我问的原因是我从一个外部API读取数据,他们说“您应该只得到1个答案,但是当您得到更多答案时,请使用最后一个答案”,而最后一个是文本中的最后一个答案,因此在本例中为“ 50”。

1 个答案:

答案 0 :(得分:1)

是的,您可以依靠通过JsonSerializer读取的数组节点的顺序。 JSON数组被定义为按排序的值的集合。。Json.NET会按照在JSON文件中遇到的顺序将它们添加到您的集合中。

这可以通过检查source code来验证。方法JsonSerializerInternalReader.CreateList()是负责集合反序列化的顶级方法,它具有以下三种基本情况:

  1. 反序列化为读/写集合时,将按从JSON流中读取值的顺序调用ICollection.Add()(或ICollection<T>.Add()),从而保留JSON数组的顺序。可以在JsonSerializerInternalReader.PopulateList()中看到。

    (当集合缺少非通用的Add(object value)方法时,将创建一个CollectionWrapper<T>来处理强制转换为所需参数类型的操作,但是这完全不影响算法,因为包装器立即调用基础集合的Add(T Value)方法。)

  2. 反序列化为.Net数组时,会为一些适当的List<T>创建一个临时T,并按照情况1的顺序通过{{1}添加值。 }或JsonSerializerInternalReader.PopulateMultidimensionalArray()。随后,通过依次调用Array.CreateInstance然后List<T>.ICollection.CopyTo(Array, Int32)CollectionUtils.ToMultidimensionalArray()将列表转换为数组。两者都创建一个数组,以保留传入集合的值顺序。

  3. 在反序列化不可变集合时,该集合必须具有采用JsonSerializerInternalReader.PopulateList()的构造函数,其中IEnumerable<T>是集合项类型。 release notes for Json.NET 6.0.3中对此进行了解释:

      

    对于将来所有不可变.NET集合的创建者:如果T的集合具有一个使用T的构造函数,那么Json.NET将在反序列化到您的集合时自动运行,否则您将很不走运。

    假设您的不可变集合具有所需的构造函数,算法将按照情况2进行处理,反序列化为IEnumerable<T>,然后从列表中构造碰到的不可变集合,并按遇到和反序列化的顺序排列值。

当然,集合本身可能会改变值的顺序:

但是对于基本集合IEnumerable<T>List<T>,这不会发生。