问题描述
我正在追踪一个错误,我注意到 Newtonsoft JSON 会将项目附加到已在默认构造函数中初始化的 List<>
中.我在 C# 聊天中与一些人进行了更多挖掘和讨论,我们注意到这种行为不适用于所有其他集合类型.
I was tracking down a bug and I noticed that Newtonsoft JSON will append items to a List<>
that's been initialized in the default constructor. I did a little more digging and discussed with some people on the C# chat and we noticed that this behavior doesn't apply to all other collection types.
https://dotnetfiddle.net/ikNyiT
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Collections.ObjectModel;
public class TestClass
{
public Collection<string> Collection = new Collection<string>(new [] { "ABC", "DEF" });
public List<string> List = new List<string>(new [] { "ABC", "DEF" });
public ReadOnlyCollection<string> ReadOnlyCollection = new ReadOnlyCollection<string>(new [] { "ABC", "DEF" });
}
public class Program
{
public static void Main()
{
var serialized = @"{
Collection: [ 'Goodbye', 'AOL' ],
List: [ 'Goodbye', 'AOL' ],
ReadOnlyCollection: [ 'Goodbye', 'AOL' ]
}";
var testObj = JsonConvert.DeserializeObject<TestClass>(serialized);
Console.WriteLine("testObj.Collection: " + string.Join(",", testObj.Collection));
Console.WriteLine("testObj.List: " + string.Join(",", testObj.List));
Console.WriteLine("testObj.ReadOnlyCollection: " + string.Join(",", testObj.ReadOnlyCollection));
}
}
输出:
testObj.Collection: ABC,DEF
testObj.List: ABC,DEF,Goodbye,AOL
testObj.ReadOnlyCollection: Goodbye,AOL
如您所见,Collection<>
属性不受反序列化的影响,List<>
被附加到 ReadOnlyCollection<>
代码> 被替换.这是预期的行为吗?原因是什么?
As you can see the Collection<>
property is unaffected by deserialization, the List<>
is appended to and ReadOnlyCollection<>
is replaced. Is this intended behavior? What was the reasoning?
推荐答案
基本上归结为类型实例化和ObjectCreationHandling
设置.ObjectCreationHandling
It basically boils down to type instantiation and the ObjectCreationHandling
setting. There are three settings for ObjectCreationHandling
Auto 0 重用现有对象,在需要时创建新对象.
重用 1 仅重用现有对象.
Replace 2 总是创建新的对象.
Auto 0 Reuse existing objects, create new objects when needed.
Reuse 1 Only reuse existing objects.
Replace 2 Always create new objects.
默认为 auto
(第 44 行).
Auto 仅在一系列检查确定当前类型是否有一个为空的 TypeInitializer
之后才会被覆盖.此时它会检查是否存在无参数构造函数.
Auto is only overwritten after a series of checks which determine if the current type has a TypeInitializer
which is null. At that point it checks if there is a parameterless constructor.
///
///创建一个工厂函数,该函数可用于创建由
描述的 JsonConverter 的实例///参数类型.
///然后可以使用返回的函数来调用转换器的默认 ctor,或任何
///通过对象数组的方式参数化构造函数.
///
///
/// Create a factory function that can be used to create instances of a JsonConverter described by the
/// argument type.
/// The returned function can then be used to either invoke the converter's default ctor, or any
/// parameterized constructors by way of an object array.
///
基本上它的行为是这样的(它看起来是 6 个类中大约 1500 行代码).
Essentially it acts like this (what it looks like is about 1500 lines of code in 6 classes).
ObjectCreationHandling och = ObjectCreationHandling.Auto;
if( typeInitializer == null )
{
if( parameterlessConstructor )
{
och = ObjectCreationHandling.Reuse;
}
else
{
och = ObjectCreationHandling.Replace;
}
}
此设置是 JsonSerializerSettings 的一部分,由 DeserializeObject 的访问者模式构造函数内部组成.如上所示,每个设置都有不同的功能.
This setting is a part of the JsonSerializerSettings which are composed inside of the visitor pattern constructor for DeserializeObject. As shown above, each setting has a different function.
回到 List、Collection 和 ReadOnlyCollection,我们将查看每个条件语句的集合.
Getting back to List, Collection, and ReadOnlyCollection, we will look at the set of conditional statements for each.
列表
testObj.List.GetType().TypeInitializer == null
为假.结果,List
接收默认的 ObjectCreationHandling.Auto 并且在反序列化期间使用 testObj 实例的实例化 List,以及使用 serialized
字符串实例化的新 List.
testObj.List.GetType().TypeInitializer == null
is false. As a result, List
receives the default ObjectCreationHandling.Auto and the instantiated List for the testObj instance is used during deserialization, as well as a new List being instantiated with the serialized
string.
testObj.List: ABC,DEF,Goodbye,AOL
收藏
testObj.Collection.GetType().TypeInitializer == null
为 true 表示没有可用的反射类型初始化器,因此我们进入下一个条件,即检查是否存在无参数构造函数.testObj.Collection.GetType().GetConstructor(Type.EmptyTypes) == null
为假.结果,Collection
接收到 ObjectCreationHandling.Reuse 的值(仅重用现有对象).Collection 的实例化实例是从 testObj 使用的,但是 serialized
字符串无法实例化.
testObj.Collection.GetType().TypeInitializer == null
is true indicating there was no reflected type initializer available, so we go to the next condition which is to check if there is a parameterless constructor. testObj.Collection.GetType().GetConstructor(Type.EmptyTypes) == null
is false. As a result Collection
receives the value of ObjectCreationHandling.Reuse (only reuse existing objects). The instantiated instance for Collection is used from testObj, but the serialized
string is not able to be instantiated.
testObj.Collection: ABC,DEF
ReadOnlyCollection
testObj.ReadOnlyCollection.GetType().TypeInitializer == null
为 true 表示没有可用的反射类型初始化器,所以我们进入下一个条件,即检查是否存在无参数构造函数.testObj.ReadOnlyCollection.GetType().GetConstructor(Type.EmptyTypes) == null
也是如此.结果,ReadOnlyCollection 接收到 ObjectCreationHandling.Replace 的值(总是创建新对象).仅使用 serialized
字符串中的实例化值.
testObj.ReadOnlyCollection.GetType().TypeInitializer == null
is true indicating there was no reflected type initializer available, so we go to the next condition which is to check if there is a parameterless constructor. testObj.ReadOnlyCollection.GetType().GetConstructor(Type.EmptyTypes) == null
is also true. As a result ReadOnlyCollection recieves the value of ObjectCreationHandling.Replace (always create new objects). Only the instantiated value from the serialized
string is used.
testObj.ReadOnlyCollection: Goodbye,AOL
这篇关于使用 Newtonsoft JSON 的 ObjectCreationHandling 说明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!