原文地址:https://devblogs.microsoft.com/dotnet/whats-next-for-system-text-json/
最近实习有用到json的序列化和反序列化,在查找资料的过程中发现了这篇文章,这篇文章以库作者的视角介绍System.Text.Json
,感觉视角一下拔高了许多。于是在空闲之余翻译了此文。
路漫漫其修远兮,吾将上下而求索。
第一次尝试翻译这么长的博客,有误之处敬请提出,以免由于我的失误免误导他人。
以下是正文:
刚刚发布的.NET 5.0带来了许多新特性(new features)和一系列性能提升。System.Text.Json
也不例外。我们改进了它的性能、可靠性,同时使其更容易被那些熟悉Newtonsoft.Json
的开发人员使用。在这篇文章中,我将会讨论System.Text.Json
取得的进展和未来的发展方向。
获取System.Text.Json
库
- 如果你的项目目标框架为.NET 5,.NET 5提供了开箱即用的
System.Text.Json
库,无需其它先决条件。点此下载.NET 5。 - 如果你的项目目标框架为.NET Core 3.x或者.NET Framework,或者你想要构建一个.NET Standard兼容库,请安装最新的System.Text.Json NuGet包。
- 如果你正在进行一个新的ASP.NET Core项目或者正在将一个已经存在的ASP.NET Core 2.2项目从2.2升级到3.0或5.0,
System.Text.Json
将会是新项目和升级项目默认使用的序列化库。
什么是System.Text.Json
?
System.Text.Json
是.NET内置的用于.NET对象类型和JSON字符串相互转换的JSON(JavaScript Object Notation, JS 对象简谱)序列化库,并且支持UTF-8编码。它在.NET Core 3.0被添加进来。在这个库中,使用最为频繁的类型当属JsonSerializer
,此类型提供了最直接的(highest level of functionality)处理JSON数据的功能。这里有一个简单的示例向你展示如何使用此库序列化和反序列化JSON数据:
using System;
using System.Text.Json;
MyType obj = new() { Message = "Hello World!" };
string json = JsonSerializer.Serialize(obj);
Console.WriteLine(json); // {"Message":"Hello World!"}
MyType anotherObject = JsonSerializer.Deserialize<MyType>("{"Message":"Hello Again."}");
Console.WriteLine(anotherObject.Message); // "Hello Again."
public class MyType
{
public string Message { get; set; }
}
为什么使用System.Text.Json
?回顾.NET Core 3.x以寻找答案。
处理JSON数据已经成为现代.NET程序中必不可少的一环,在许多情况下,JSON的使用甚至已经超过了XML。然而,.NET框架中并没有一个很好处理JSON数据的内置方法。所以,此前用户只能依赖Newtonsoft.Json
,Newtonsoft.Json
持续为.NET生态提供了很棒的服务,显然,用户将从集成在框架中的现代JSON库获益。因此,我们基于以下几点考虑构建了一个新的JSON库:
- **提供一批高性能的JSON处理API。**我们需要一个针对性能进行深度调优的JSON API集,利用诸如
Span<T>
的框架新特性,获得直接处理UTF-8编码(无需将其转码至UTF-16字符串)的能力。性能优化对于ASP.NET Core至关重要,因为吞吐量是ASP.NET Core的关键需求。我们曾考虑过促成Newtonsoft.Json
的升级,但我们认为要做到既能延续Newtonsoft.Json
用户的使用体验也不牺牲我们本可以达到的性能是不可能的。 - **从ASP.NET Core中移除
Newtonsoft.Json
依赖。在.NET Core 3.x之前,ASP.NET Core都有着对Newtonsoft.Json
的依赖。**虽然.NET Core 3.x之前提供了ASP.NET Core和Newtonsoft.Json
之间紧密的连接,这也意味着Newtonsoft.Json
的版本由基础平台决定。然而,Newtonsoft.Json
有着频繁的更新,应用开发者们经常需要使用一个特定的版本。因此,我们想要从ASP.NET Core 3.0中移除对Newtonsoft.Json
的依赖,以便开发者们能够自由选择他们想要使用的版本而不用担心因为Newtonsoft.Json
版本和基础平台关联导致的可能发生的意外。
考虑到Newtonsoft.Json
在.NET生态中无所不在,我们不希望从ASP.NET Core中移除Newtonsoft.Json
依赖后没有一个简单的方法去重新获取一个作为序列化机制的Newtonsoft.Json
。以下为提供的简便方法:
- 下载Microsoft.AspNetCore.Mvc.Newtonsoft.Json NuGet包。
- 更新
Startup.ConfigureServices()
以调用AddNewtonsoftJson()
。
services.AddMvc().AddNewtonsoftJson();
有关更多信息,见Newtonsoft.Json(Json.NET)support.
.NET Core 3.0中的新内容
在.NET Core 3.0中,我们在System.Text.Json命名空间中提供了以下类型:
- JsonSerializer: 提供将.NET对象序列化成JSON格式和将JSON反序列化成.NET对象的方法。
- JsonDocument: 提供随机访问的能力以检查JSON值的结构内容而不需自动化实例数据值。此类型是不可变的(immutable type)。
- JsonElement: 表示
JsonDocument
中的特定JSON值。 - Utf8JsonWriter: 提供高性能API,用于对UTF-8编码的JSON文本的仅前向,非缓存写入。
- Utf8JsonReader: 提供高性能API,用于对UTF-8编码的JSON文本进行仅转发的逐令牌处理。
在System.Text.Json.Serialization命名空间中,我们提供了一些用于高级场景和用户定制的属性和API,这些属性和API特定于JsonSerializer
的序列化和反序列化。其中使用最多的为JsonConverter<T>
类型,此类型允许用户控制序列化和反序列化特定的类型、属性、字段。
JsonSerializer
提供了最直接的处理JSON数据的功能。由于实现一个用于持久性数据格式(a persistent data format)和.NET对象类型之间转换的序列化器需要极其宽阔广泛的功能,与JSON相关的其它类型相比,JsonSerializer
正在进行更多的开发并且受到更多的社区反馈。因此,本文将主要介绍JsonSerializer
的功能。
在3.0版本,我们提供了具有以下功能的JsonSerializer
:
- 支持对简单传统CLR对象(POCO)、基元类型、集合进行序列化和反序列化;
- 内置的异步序列化和反序列化;
- 原生处理UTF-8数据;
- 反序列化可选是否区分大小写;
- 使用
JsonNamingPolicy.CamelCase
的驼峰命名策略; - 使用
JsonNamingPolicy
指定自定义命名策略; - 转义的JSON数据反序列化;
- 序列化时可选的最小字符转义;
- 序列化时忽略空值;
- 反序列化时忽略注释;
- 允许(JSON)尾随逗号;
- 可定制转换器;
- 使用
[JsonExtensionData]
特性指示在反序列化时没有匹配成员的属性存放处(a property overflow bag);(注:当属性的类型为IDictionary<TKey,TValue>
时,没有匹配成员的任何属性都会在反序列化期间添加到该字典中,并在序列化期间中写入) - 使用
[JsonIgnore]
特性忽略特定的属性; - 使用
[JsonProperty]
特性来指定自定义属性名。(注:未使用[JsonProperty]
特性时Json对应的实体类属性名需要与Json对应属性完全一致,使用[JsonProperty]
特性标识PropertyName
后,实体类属性名可自定义)
有关System.Text.Json
提供的功能概述,见.NET 中的 JSON 序列化和反序列化(封送和拆收)。
如何在System.Text.Json
和Newtonsoft.Json
中做出选择?
功能差异
现在,你也许在问自己,我应该从NewtonsoftJson
迁移到System.Text.Json
吗?
答案是,这取决于你更相信哪个。在.NET Core 3.0,我们让System.Text.Json
成为了ASP.NET Core的默认序列化程序,原因在于我们相信对于大部分应用程序来说它已经足够好。但是,如果你对序列化行为进行了高度自定义,例如使用了数个Newtonsoft.Json
的特性,则相对于大多数使用POCO的人而言,迁移可能会更加困难。更多详细信息,请阅读如何从 Newtonsoft.Json 迁移到 System.Text.Json。
考虑到System.Text.Json
是新.NET应用程序默认的JSON处理集(JSON-processing stack),它主要关注程序性能、安全性和标准合规性。它在默认行为上和Newtonsoft.Json
有着巨大差异,并非旨在与Newtonsoft.Json
具有同等功能。在某些情况下,System.Text.Json
没有提供可用的内置功能,但会有推荐的替代方案(也存在替代方案不切实际的情况)。如果您的应用程序依赖System.Text.Json
缺失的功能,请考虑在github上filing an issue以了解是否可以添加对您的方案的支持。
这并不是说System.Text.Json没有足够的功能或灵活性,也不是说Newtonsoft.Json速度慢(注:feature(functionality)、flexibility、speed三者不可兼得);只是阐述不同的设计理念,以及当功能与性能或灵活性发生冲突时我们如何权衡其中做出选择。我们对System.Text.Json
的期望是提供一个内置的平衡性能、安全性、功能性的高速JSON处理方式。每一个功能要求均会根据这些设计原则仔细权衡。这可能意味着符合这些原则的新项目可能更容易使用System.Text.Json
,而较旧的项目在迁移过程中可能会遇到更多的障碍。然而,使用Newtonsoft.Json
则没有这些问题,使用System.Text.Json
或者继续使用Newtonsoft.Json
,随你心意。
这里提供两个我们在目前的计划表中没有打算加入到System.Text.Json
的特性:
- 类型转换。你可以使用
System.ComponentMode.TypeConverter
。 - 调整序列化行为。你可以使用
System.Runtime.Serialization
的特性。
以上两者都被认为是旧系统遗留下来的序列化集,由于在启动时进行了额外的基于反射的查找,在System.Text.Json.dll中增加更多的代码也将带来维护和容量负担,因此,支持以上功能将与System.Text.Json
的性能优先原则相悖。此外,任何有可能违反我们的标准合规性原则的功能(例如允许在反序列化时处理格式错误的JSON)均不会被接受。
我们在设计System.Text.Json
时就考虑到了扩展性,这意味着即使在JsonSerializer
中没有原生支持的功能也能够通过用户配置来实现。例如,用户可以使用自定义JsonConverter<T>
将TypeConverter
包装起来。我们也考虑使用IContractResolver
和类似JsonProperty
的机制(来自Newtonsoft.Json
)来允许以编程的方式设置元数据和有关类和成员的序列化逻辑(dotnet/runtime #31257),这将允许对Sytem.Runtime.Serialization
特性有着最高级的自定义支持。(which would allow custom support for honoring System.Runtime.Serialization
attributes)
JsonSerializer
有着内置、高效的异步序列化和反序列化JSON数据功能。事实证明,这对于编写具有响应性和非阻塞性的高度可扩展应用程序的用户具有巨大价值。而Newtonsoft.Json
没有支持异步处理JSON的机制。
UTF-8编码是用于在线信息传输的实际格式。Sytem.Text.Json
的API原生使用UTF-8处理数据而不像Newtonsoft.Json
需要转码到UTF-16进行处理。调用者在将数据作为输入传递到System.Text.Json
API之前也无需进行手动转换。避免这种转换也有助于在处理JSON数据时获得更佳性能。请注意,基于字符串的(UTF-16)API虽然提供了便利,但会带来转码的成本。
性能
在.NET Core 3.0开发周期中,我们曾经在一篇博客(Try the new System.Text.Json APIs)中介绍了System.Text.Json
性与Newtonsoft.Json
之间的性能比较:
情境 | 速度 | 内存占用 |
---|---|---|
反序列化 | 2倍速 | 相同或更低 |
序列化 | 1.5倍速 | 相同或更低 |
Document(read-only) | 3-5倍速 | ~Allocation free for sizes < 1 MB |
写 | 2-3倍速 | ~Allocation free (until you materialize values) |
读 | 1.3-1.6倍速 | ~Allocation free |
注:~Allocation free
没太明白啥意思。
与任何性能基准一样,测试情境不同,结果会产生细微差别。该帖子的摘要如下:
我们的主要目标是性能,我们看到Json.NET的典型速度提高至2倍速,但这取决于您的方案和工作负载,因此请确保衡量过对你而言重要的部分。
有些人认为这意味着System.Text.Json
总是快了一倍,但是速度提升可不能这么认为,要记住速度提升和方案、工作负载是息息相关的。
现在在JsonSerializer
和其它.NET生态中的序列化库之间已经有了一些性能对比结果,你也许已经注意到了JsonSerializer
不总是最快的,你可能想知道为什么我们将性能作为一个首要目标却出现了这个情况。在软件中,几乎不可能在不损害其它功能的情况下将某一个功能做到最大化,因此所有功能都是各个方面之间权衡出来的结果。尽管对JSON的序列化性能对我们来说是非常重要的目标,但这仅仅是目标之一。我们的目标还包括了安全性,可靠性,标准合规性和可用性。
以下是一些我们在权衡之中牺牲了性能的例子:
- 在某些情况下使用类。我们决定将
Utf8JsonWriter
写成了一个类。它曾经是一个ref struct
结构,ref struct
允许更少的内存分配和更快的存取速度(faster access to the underlying span we’re writing to)。我们将其更改为一个类,以避免开发人员意外创建writer的副本(例如,将其按值传递给helper方法时)的情况,随后的写操作最终会覆盖缓冲区中的数据。 - 验证操作。我们决定在处理JSON数据时首先进行验证,包括UTF-8编码验证和JSON语法验证。这对于启用服务器和云方案(其中JSON输入通常来自不受信任的来源)是必要的。
- 可扩展性。序列化器具有注册自定义转换器的功能。这种间接操作相对来说消耗不大,但是在紧密循环中运行时代价很高,即使在不使用它们的时候(由于查找操作)。
.NET 5.0中的新内容
新特性
在.NET 5.0中,我们实现了一些社区中最受欢迎的功能,并让使用Newtonsoft.Json
的人更容易适应。以下是所添加功能的概述:
GitHub Issue | Description |
---|---|
#30820 | 添加(反)序列化时保留对象引用的机制 |
#32937 | 为HttpClient 和HttpContent 添加扩展方法使其能够(反)序列化JSON |
#30255 | 支持(反)序列化带引号的数字 |
#29895 | 支持使用参数化构造函数反序列化对象 |
#876 | 支持(反)序列化字段 |
#779 | 支持忽略值类型默认值 |
#30687 | 支持有条件地忽略属性(always,never,when null/default) |
#30524 | 支持非字符串字典键(non-string dictionary keys) |
#29743 | 允许使用非公共属性访问器进行(反序列化) |
#34439 | 为自定义转换器提供处理null值的选项 |
#38539 | 支持新的C# recored 类型 |
#30445 | 将复制构造函数添加到JsonSerializerOptions |
#34626 | 为JsonSerializerOptions 添加采用序列化默认值的构造函数 |
#31326 | 使得JsonSerializer能够在Xamarin iOS / Android上运行 |
当我们宣布.NET 5.0和.NET 5.0 RC 1时,我们介绍了一些新功能,包括改进了对不可变类型的支持,并在JSON对象图中保留引用(preserving references in JSON object graphs)。在本节中,我将介绍更多内容。
支持带引号的数字
.NET Core 3.0时代,默认情况下不支持反序列化编码为JSON字符串的数字类型。解决方法是为每个适用的数字类型添加一个自定义转换器,该转换器将控制该类型的序列化和反序列化,包括处理带引号数字的逻辑。在.NET 5中,我们添加了一个便捷的选择加入功能来支持对带引号的数字进行序列化和反序列化,并命名浮点字面量(NaN,Infinity和-Infinity)。例子如下:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
var options = new JsonSerializerOptions
{
NumberHandling = JsonNumberHandling.AllowReadingFromString |
JsonNumberHandling.WriteAsString
};
string json = @"{""NumberOne"":1,""NumberTwo"":""2""}";
ClassWithInts @class = JsonSerializer.Deserialize<ClassWithInts>(json, options);
Console.WriteLine(@class.NumberOne); // 1
Console.WriteLine(@class.NumberTwo); // 2
json = JsonSerializer.Serialize(@class, options);
Console.WriteLine(json); // @"{""NumberOne"":""1"",""NumberTwo"":""2""}";
public class ClassWithInts
{
public int NumberOne { get; set; }
public int NumberTwo { get; set; }
}
除了全局应用的JsonSerializerOptions.NumberHandling选项外,我们还添加了JsonNumberHandlingAttribute特性,它可以为类型,属性或字段指定数字处理设置。
支持忽略默认值
在.NET Core 3.x序列化操作时,只能忽略用于引用或可为空值类型的null值,JsonSerializerOptions.IgnoreNullValues
仅适用于整个JSON对象图(注:我的理解为整个JSON,没有单独标识属性和字段的能力)。在.NET 5中,我们增加了可以忽略非空值类型的默认值的支持,例如int和float。此外,现在可以选择默认情况下忽略的属性和字段。示例如下:
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
var obj = new MyClass();
string json = JsonSerializer.Serialize(obj, options);
Console.WriteLine(json); // {"MyBool":false}
public class MyClass
{
public int MyInt { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public bool MyBool { get; set; }
public string MyString { get; set; }
}
在这里,我们看到了这些新功能的组合:我们告诉序列化程序忽略整个对象图的默认值,但标记了无论全局选项如何,都不忽略其中MyBool
属性的默认值。要仅忽略空值,而不是值类型的默认值,请使用JsonIgnoreCondition.WhenWritingNull
。
现在我们可以通过这些扩展来处理默认值,JsonSerializerOptions.IgnoreNullValues
属性将在未来的.NET 6.0版本中标记过时[Obsolete]
。我们不希望IgnoreNullValues
在序列化和反序列化时成为最优先的选项,因为没有充分的理由在输入中忽略空值。
JsonSerializerOptions
的实用构造函数
将JsonSerializerOptions
设置从一个实例复制到另一个实例,然后进行一些更改是一种常见的操作。在.NET 5中,我们向JsonSerializerOptions
添加了一个复制构造函数,这使此操作变得更加容易:
JsonSerializerOptions options = new()
{
NumberHandling = JsonNumberHandling.AllowReadingFromString,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
Converters = { new JsonStringEnumConverter() }
};
JsonSerializerOptions newOptions = new(options)
{
NumberHandling = JsonNumberHandling.Strict
};
Console.WriteLine(newOptions.NumberHandling);
// Strict
Console.WriteLine(newOptions.DefaultIgnoreCondition);
// WhenWritingNull
Console.WriteLine(newOptions.Converters[0]);
// System.Text.Json.Serialization.JsonStringEnumConverter
在Web上下文中处理JSON数据时,一组常见的选项是使用驼峰(camelCase)命名策略,在反序列化时指定不区分大小写的匹配,并允许读取带引号的数字。新的JsonSerializerDefaults.Web
枚举值以及采用JsonSerializerDefaults
值的新构造函数,提供了一种在应用程序的多个层(例如,Blazor场景的客户端(反序列化),传输时(序列化)和服务器(反序列化和序列化))中以一致的方式重用这些选项的简便方法(意思是可以通过JsonSerializerDefaults
初始化JsonSerializerOptions
,这样可以让保持相同的序列化选项变得更容易)。让我们来看看:
JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
Console.WriteLine(options.PropertyNamingPolicy);
// System.Text.Json.JsonCamelCaseNamingPolicy
Console.WriteLine(options.PropertyNameCaseInsensitive);
// True
Console.WriteLine(options.NumberHandling);
// AllowReadingFromString
与Newtonsoft.Json
相比,有关JsonSerializer
支持哪些功能的更多信息,请参阅迁移指南中的此表。
性能提升
在.NET Core 3.1和.NET 5之间,我们在以下方面提高了性能:
- 提升了集合序列化和反序列化时性能
- 提升了small types(小型类型?)的序列化和反序列化性能
- 提升了不区分大小写和缺少属性的情况下的反序列化性能
- 提升了长JSON字符串的序列化性能
这些改进尤其对于高性能应用程序特别有意义。
提升集合性能
我们针对大型集合进行了重大改进(反序列化为〜1.15x-1.5x,序列化为〜1.5x-2.4x)。您可以在dotnet / runtime#2259中看到这些改进的详细信息。以下数字显示处理具有1,024个元素的集合的性能数字。
Dictionary<string, string>
(图表省略,详见上文github pull链接)
List<int>
(图表省略,详见上文github pull链接)
提升了small types的性能(TechEmpower benchmarks)
在.NET 5.0中,我们做出了巨大的努力来提高.NET性能(通过TechEmpower JSON benchmark性能测试)。这项工作涉及多个领域,包括网络堆栈,Kestrel和JsonSerializer
本身。最终,观察到串行器中完成的一项工作的性能提高了约19%。
这些更改和性能衡量标准在dotnet/runtime #37976中详细介绍,在那有两套标准展示。我们首先使用了开发团队维护的JsonSerializer performance benchmarks,性能提升了约8%。下一部分是针对TEchEmpower的,他测量了三种不同的方法来满足TechEmpower JSON测试基准。SerializeWithCachedBufferAndWriter
是我们在官方测试中使用的那个。
Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|
SerializeWithCachedBufferAndWriter (Before) | 155.3 ns | 1.19 ns | 1.11 ns | 155.5 ns | 153.3 ns | 157.3 ns | 0.0038 | – | – | 24 B |
SerializeWithCachedBufferAndWriter (After) ~1.19x faster | 130.8 ns | 1.50 ns | 1.40 ns | 130.9 ns | 128.6 ns | 133.0 ns | 0.0037 | – | – | 24 B |
一旦我们更新到.NET 5.0,我们做的包括上述所有工作都会提升.NET在JSON TechEmpower基准测试上的排名。我们可以比较.NET 3.1(Round 19,2020-05-28)和.NET 5.0(非正式连续运行,2020-12-14)中基准的aspcore条目的性能:
Before
After
我们可以看到,JSON序列化的每秒响应(RPS)从904,846增加到1,190,245,提高了约31%。
提升了不区分大小写和额外属性的情况下的反序列化性能(前面是missing-property cases,这里是extra-property cases,可能有误)
使用JSON最常见的问题之一是.NET设计准则与命名约定不匹配。JSON属性常常使用camelCase(驼峰命名法),而.NET属性和字段一般都是PascalCase(帕斯卡命名法)。您使用的JSON序列化程序有责任在命名约定之间搭建桥梁。这个操作需要的性能不可忽视,至少在.NET Core 3.1中不能,但是现在,在.NET 5.0中,你可以放心忽略这个操作消耗的性能。
.NET 5.0中大大改进了允许不区分大小写和额外属性的代码。在某些情况下,速度快约1.75倍。
下列基准测试是针对一个简单的4属性测试类,该类具有超过7个字符的属性名称。
.NET 3.1的性能测试
Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|
CaseSensitive_Matching 844.2 ns | 4.25 ns | 3.55 ns | 844.2 ns | 838.6 ns | 850.6 ns | 0.0342 | – | – | 224 B | |
CaseInsensitive_Matching | 833.3 ns | 3.84 ns | 3.40 ns | 832.6 ns | 829.4 ns | 841.1 ns | 0.0504 | – | – | 328 B |
CaseSensitive_NotMatching (Extra) | 1,007.7 ns | 9.40 ns | 8.79 ns | 1,005.1 ns | 997.3 ns | 1,023.3 ns | 0.0722 | – | – | 464 B |
CaseInsensitive_NotMatching | 1,405.6 ns | 8.35 ns | 7.40 ns | 1,405.1 ns | 1,397.1 ns | 1,423.6 ns | 0.0626 | – | – | 408 B |
.NET 5.0的性能测试
Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|
CaseSensitive_Matching 799.2 ns | 4.59 ns | 4.29 ns | 801.0 ns | 790.5 ns | 803.9 ns | 0.0985 | – | – | 632 B | |
CaseInsensitive_Matching | 789.2 ns | 6.62 ns | 5.53 ns | 790.3 ns | 776.0 ns | 794.4 ns | 0.1004 | – | – | 632 B |
CaseSensitive_NotMatching (Extra) | 479.9 ns | 0.75 ns | 0.59 ns | 479.8 ns | 479.1 ns | 481.0 ns | 0.0059 | – | – | 40 B |
CaseInsensitive_NotMatching | 783.5 ns | 3.26 ns | 2.89 ns | 783.5 ns | 779.0 ns | 789.2 ns | 0.1004 | – | – | 632 B |
提升了长JSON字符串的序列化性能
dotnet / corefx#41845利用SSE2内部函数进行安全检查,以更快地查看JSON字符串是否需要转义。序列化常见的有效负载时,性能可提高约10-20%。同样,直接写入相对较大的JSON字符串时,性能提高约30%。在此GitHub gist中将更详细地讨论此更改的性能特征。
重大变化
我们在.NET Core 3.x和.NET 5.0之间进行了一些行为上的重大更改。鉴于System.Text.Json
是平台组件,并且像.NET其余部分一样遵循严格的兼容性标准,因此,这些更改是在仔细评估其影响的基础上进行的。尽管很重要,但这些更改通常解决了一些极端情况,尤其是在一致性方面,并且对使用该库的绝大多数人的影响应该很小。对于更多更重要的行为更改和新功能的增加,我们以避免破坏针对该库先前版本编写的现有代码的情况下让其加入。有关每个重大更改的更多信息,请参见链接的文档。
- System.Text.Json 需要使用单字符字符串才能反序列化 char
- ASP.NET Core 应用允许反序列化带引号的数字
- JsonSerializer.Serialize 在类型参数为 null 时引发 ArgumentNullException
- 非公共的无参数构造函数不用于反序列化
- 对键值对进行序列化和反序列化时,使用“PropertyNamingPolicy”、“PropertyNameCaseInsensitive”和“Encoder”选项
System.Text.Json的下一步
我们已经开始了.NET 6.0的计划。我们将继续增加最需要的特性,这将帮助Sytem.Text.Json
成为更多.NET应用的JSON协议栈的可行选择,在这个过程中,我们将根据我们的设计原则来增加每一个特性。有关所建议内容的概述,请参见dotnet/runtime 43620。这是一些主要功能的先驱。
JSON序列化的C#源生成器(dotnet/runtime #1568)
应用领域之一是利用新的C#源生成器功能来生成可在以下方面帮助序列化程序的代码:
- 改进的启动性能
- 改进的运行时吞吐量
- 减少了专用字节使用量(由于避免了运行时反射)
- ILLinker友好性
- 通过促进链接器删除序列化器和未使用的基于反射的未使用代码路径而减少了应用程序的大小
这项工作正在进行中,并且处于原型阶段。正在进行的项目和工作进度可以通过dotnet/runtimelab中的JSON Code Gen project board观察。
可以通过实验性的NuGet包使用支持源生成的更新后的System.Text.Json
。请与我们分享您在使用此功能时观察到的任何性能变化。使用area-JsonCodeGen标签在此处记录问题。
扩展的多态序列化和反序列化(dotnet/runtime #45189)
多态序列化和反序列化仍然是现代.NET应用程序的重要方案。我们希望在.NET 6.0中进行功能工作以启用这些方案。
动态且可变的JSON DOM(dotnet/runtime #45188)
启用序列化和反序列化dynamic
类型以及提供可变的JSON文档是两个紧密相关且重要的功能,它们将阻止许多客户。我们正在将它们作为.NET 6.0的潜在工作项目进行跟踪。
杂项改进(dotnet/runtime #45190)
我们希望在.NET 6.0中进行多项其他功能和改进。有些功能是System.Text.Json
的创新和独特功能,例如支持IAsyncEnumerable<T>
实例的异步序列化和反序列化的功能(dotnet/runtime #1570)。其他功能将更加熟悉,例如添加了snake_case支持(dotnet / runtime#782),并能够更改默认的JsonSerializerOptions
设置(dotnet / runtime#31094)。实施这些功能将使得System.Text.Json
适合更多应用程序。
结语
.NET 5.0是System.Text.Json
的重要版本。如果您的项目未针对.NET 5.0,则仍然可以通过安装最新的System.Text.Json NuGet包来利用新的改进。
我们在.NET 5.0中所做的许多工作都是由社区推动的。@YohDeadfall implemented field support and contributed various optimizations to JsonSerializer
. @NikiforovAll implemented the JsonSerializerOptions constructor that takes a JsonSerializerDefaults value. @marcusturewicz implemented support for serializing and deserializing JsonDocument instances. @devsko contributed fixes to various issues with new .NET 5.0 improvements before we shipped. @CodeBlanch contributed fixes for issues with null
and nullability. @Marusyk contributed a fix for a bug with reference equality for the new preserve-references feature. @khellang contributed a fix for a bug with the validation of DateTime
and DateTimeOffset
payloads when reading. @alanisaac, @thomaslevesque, @marcusturewicz, @madmir, @NikiforovAll, @JoshSchreuder, @Jacksondr5, and @KimKiHyuk contributed changes to improve test coverage for System.Text.Json in the continuous effort to get it close to 100%. We can’t highlight all the contributions here, but the .NET Thanks page gives kudos to all contributors to the .NET runtime.
在.NET 6.0中,我们将继续进行更多改进。我们非常欢迎对System.Text.Json
的贡献,让我们一起造就在.NET 6.0的进步。只需访问此GitHub query,即可找到标有area-System.Text.Json
和up-for-grabs
的issues。如果您觉得可以更进一步,请检查没有up-for-grabs
标签的问题。与往常一样,非常欢迎您提供反馈,尤其是现在,因为我们正在计划下一个版本。
—end—
恭喜看完!
因为一些原因走了弯路,接下来努力在毕业之前朝将自己补完的目标前进!!!!!!!!