我正在追踪一个错误,我注意到Newtonsoft JSON会将项目附加到List<>已在默认构造函数中初始化的项目中.我做了一些挖掘并与C#chat上的一些人讨论过,我们注意到这种行为并不适用于所有其他集合类型.
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));
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
testObj.Collection: ABC,DEF
testObj.List: ABC,DEF,Goodbye,AOL
testObj.ReadOnlyCollection: Goodbye,AOL
Run Code Online (Sandbox Code Playgroud)
如您所见,该Collection<>属性不受反序列化的影响,将List<>附加到并ReadOnlyCollection<>替换.这是预期的行为吗?是什么原因?
Tra*_*s J 10
它基本归结为类型实例化和ObjectCreationHandling设置.有三种设置ObjectCreationHandling
自动0重新使用现有对象,在需要时创建新对象.
重用1仅重用现有对象.
替换2始终创建新对象.
默认值为auto(第44行).
只有在一系列检查确定当前类型是否TypeInitializer为null 之后,才会覆盖Auto .此时它会检查是否存在无参数构造函数.
///
///创建一个工厂函数,可用于创建由
///参数类型描述的JsonConverter实例.
///然后可以使用返回的函数
通过对象数组调用转换器的默认ctor或任何///参数化构造函数.
///
基本上它就像这样(它看起来像6行中的大约1500行代码).
ObjectCreationHandling och = ObjectCreationHandling.Auto;
if( typeInitializer == null )
{
if( parameterlessConstructor )
{
och = ObjectCreationHandling.Reuse;
}
else
{
och = ObjectCreationHandling.Replace;
}
}
Run Code Online (Sandbox Code Playgroud)
此设置是JsonSerializerSettings的一部分,它们在DeserializeObject的访问者模式构造函数内部组成.如上所示,每个设置具有不同的功能.
回到List,Collection和ReadOnlyCollection,我们将查看每个条件语句的集合.
名单
testObj.List.GetType().TypeInitializer == null是假的.因此,List接收默认的ObjectCreationHandling.Auto,并在反序列化期间使用testObj实例的实例化List,以及使用该serialized字符串实例化的新List .
testObj.List: ABC,DEF,Goodbye,AOL
Run Code Online (Sandbox Code Playgroud)
采集
testObj.Collection.GetType().TypeInitializer == null为true表示没有可用的反射类型初始值设定项,因此我们转到下一个检查是否存在无参数构造函数的条件.testObj.Collection.GetType().GetConstructor(Type.EmptyTypes) == null是假的.结果Collection收到ObjectCreationHandling.Reuse的值(仅重用现有对象).Collection的实例化实例用于testObj,但该serialized字符串无法实例化.
testObj.Collection: ABC,DEF
Run Code Online (Sandbox Code Playgroud)
ReadOnlyCollection
testObj.ReadOnlyCollection.GetType().TypeInitializer == null为true表示没有可用的反射类型初始值设定项,因此我们转到下一个检查是否存在无参数构造函数的条件.testObj.ReadOnlyCollection.GetType().GetConstructor(Type.EmptyTypes) == null也是如此.因此,ReadOnlyCollection接收ObjectCreationHandling.Replace的值(始终创建新对象).仅serialized使用字符串中的实例化值.
testObj.ReadOnlyCollection: Goodbye,AOL
Run Code Online (Sandbox Code Playgroud)