c# - 使用 Newtonsoft JSON 的 ObjectCreationHandling 的说明?

标签 c# json.net

我正在追踪一个错误,我注意到 Newtonsoft JSON 会将项目附加到 List<>已在默认构造函数中初始化。我在 C# 聊天中做了更多挖掘并与一些人讨论,我们注意到此行为并不适用于所有其他集合类型。

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<>被替换。这是有意的行为吗?原因是什么?

最佳答案

它基本上归结为类型实例化和 ObjectCreationHandling环境。 ObjectCreationHandling

共有三个设置

Auto 0 Reuse existing objects, create new objects when needed.
Reuse 1 Only reuse existing objects.
Replace 2 Always create new objects.

默认为自动 ( Line 44 )。

Auto 只有在确定当前类型是否有一个 TypeInitializer 为 null 的一系列检查后才会被覆盖。那时它检查是否有无参数构造函数。

///
/// 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 行代码)。

ObjectCreationHandling och = ObjectCreationHandling.Auto;
if( typeInitializer == null )
{
 if( parameterlessConstructor )
 {
  och = ObjectCreationHandling.Reuse;
 }
 else
 {
  och = ObjectCreationHandling.Replace;
 }
}

此设置是 JsonSerializerSettings 的一部分,它由 DeserializeObject 的访问者模式构造函数内部组成。如上所示,每个设置都有不同的功能。

回到 List、Collection 和 ReadOnlyCollection,我们将查看每个的条件语句集。

列表

testObj.List.GetType().TypeInitializer == null 为假。结果,List 收到默认的 ObjectCreationHandling.Auto 并且在反序列化期间使用 testObj 实例的实例化 List,以及使用 serialized 字符串实例化的新 List .

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: ABC,DEF

只读集合

testObj.ReadOnlyCollection.GetType().TypeInitializer == null 为 true 表示没有可用的反射类型初始化程序,所以我们转到下一个条件,即检查是否有无参数构造函数. testObj.ReadOnlyCollection.GetType().GetConstructor(Type.EmptyTypes) == null 也是如此。因此 ReadOnlyCollection 收到 ObjectCreationHandling.Replace 的值(总是创建新对象)。仅使用 serialized 字符串中的实例化值。

testObj.ReadOnlyCollection: Goodbye,AOL

关于c# - 使用 Newtonsoft JSON 的 ObjectCreationHandling 的说明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27848547/

相关文章:

c# - 有没有办法在序列化时自动初始化空子对象?

c# - 使用 Json.NET 序列化/反序列化具有混合类型的数组

c# - .NET 库的异常处理模式 - 处理、无人值守还是重新抛出?

C# - 将列表转储到下拉列表

c# - 使用循环或其他方式简化 C# 行

c# - JSON 无法将 JSON 数组反序列化为类型

c# - 子属性的 JSON .NET 自定义名称解析器

c# - 将不一致的json反序列化为对象c#

c# - 使用 DTOS 从 Repository 获取数据到服务层

c# - MSMQ 消息在同一台机器上总是延迟恰好 3 分钟到达