.NET Core 中 System.Text.Json 与 Newtonsoft.Json 深度对比:用法、性能与场景选型

在.NET Core 开发中,JSON 序列化与反序列化是高频操作,无论是 API 接口数据传输、配置文件解析还是缓存数据处理,都离不开 JSON 库的支持。目前.NET 生态中最主流的两款 JSON 处理库分别是微软官方内置的System.Text.Json 和第三方经典库Newtonsoft.Json( Json.NET。本文将从包特性、用法差异、性能表现、适用场景四个维度进行深度对比,并补充其他常用 JSON 库,帮助开发者做出更合适的技术选型。

一、两款 JSON 库的核心特性介绍

1.1 System.Text.Json:微软官方的 "亲儿子"

System.Text.Json 是微软在.NET Core 3.0 中正式引入的内置 JSON 处理库,后续在.NET 5/6/7/8 中持续迭代优化,旨在提供轻量、高性能且与.NET 生态深度集成的 JSON 解决方案。

核心特性:
  • 内置无需额外安装从.NET Core 3.0 开始,无需通过 NuGet 引用,直接包含在Microsoft.NETCore.App框架中(仅.NET Framework 需单独安装 NuGet 包);

  • 基于 Span优化 :底层采用Span<T>Memory<T>等现代.NET 内存操作技术,减少内存分配,降低 GC 压力;

  • 原生支持 UTF-8:直接处理 UTF-8 字节流,无需先转换为字符串,尤其适合网络传输场景(如 API 响应);

  • 严格的 JSON 规范遵循:默认仅支持 RFC 8259 标准 JSON 格式,对非标准 JSON(如注释、单引号)的兼容性较低;

  • ASP.NET** Core 深度集成**:ASP.NET Core 3.0 + 默认使用 System.Text.Json 作为 API 的 JSON 序列化器,可通过AddJsonOptions直接配置;

  • 支持 AOT 编译在.NET 7 + 中对 AOT( Ahead-of-Time )编译友好,可用于 Blazor WASM、Native AOT 等场景,而 Newtonsoft.Json 在 AOT 下存在兼容性问题。

版本支持:
  • .NET Core 3.0+ /.NET 5+ /.NET 6+ /.NET 7+ /.NET 8+(内置);

  • .NET Framework 4.6+(需安装 NuGet 包:System.Text.Json,版本需匹配框架)。

1.2 Newtonsoft.Json(Json.NET):第三方生态的 "老大哥"

Newtonsoft.Json 由 James Newton-King 开发,是.NET 生态中历史最悠久、使用最广泛的 JSON 库,早在.NET Framework 时代就成为事实上的标准,目前仍在持续维护(最新版本 13.0.3)。

核心特性:
  • 功能全面且灵活:支持复杂场景(如循环引用处理、动态类型、匿名对象序列化)、非标准 JSON(注释、单引号、尾随逗号);

  • 丰富的配置选项 :提供JsonSerializerSettings类,可精细化控制序列化行为(如日期格式、空值处理、契约解析);

  • 强大的类型支持 :原生支持DataSetDataTableExpandoObjectDynamicObject等特殊类型,System.Text.Json 需自定义转换器;

  • 成熟的生态兼容:大量第三方库(如 Entity Framework Core、Swashbuckle)、框架默认依赖 Newtonsoft.Json;

  • 文档与社区完善:存在大量教程、问题解答和自定义转换器案例,排查问题成本低。

安装方式:

通过 NuGet 安装,支持.NET Framework 4.0+、.NET Core 2.0+、.NET 5 + 等全平台:

复制代码
Install-Package Newtonsoft.Json

# 或使用.NET CLI

dotnet add package Newtonsoft.Json

二、序列化与反序列化用法对比

为了直观展示两者的差异,我们以 "用户信息" 类为例,分别对比基本用法高级配置 (日期、空值、循环引用)、特殊类型处理三类场景的代码实现。

2.1 测试模型定义

首先定义两个关联的模型类(包含循环引用场景):

复制代码
// 用户类

public class User

{

   public int Id { get; set; }

   public string Name { get; set; } = "默认用户";

   public DateTime RegisterTime { get; set; } = DateTime.Now;

   public decimal Balance { get; set; } = 0.00m;

   public Address? HomeAddress { get; set; } //  nullable引用类型

   public User? Friend { get; set; } // 用于测试循环引用

}

// 地址类

public class Address

{

   public string Province { get; set; } = string.Empty;

   public string City { get; set; } = string.Empty;

}

2.2 基本序列化 / 反序列化对比

2.2.1 System.Text.Json
复制代码
using System.Text.Json;

// 1. 创建测试对象

var user = new User

{

   Id = 1,

   Name = "张三",

   RegisterTime = new DateTime(2024, 5, 1, 10, 30, 0),

   Balance = 100.50m,

   HomeAddress = new Address { Province = "广东省", City = "深圳市" }

};

// 2. 序列化(默认配置)

string jsonStr = JsonSerializer.Serialize(user);

// 输出结果(默认格式化:紧凑模式,日期为ISO 8601格式)

// {"Id":1,"Name":"张三","RegisterTime":"2024-05-01T10:30:00","Balance":100.50,"HomeAddress":{"Province":"广东省","City":"深圳市"}}

// 3. 反序列化

User deserializedUser = JsonSerializer.Deserialize\<User>(jsonStr)!;

Console.WriteLine(deserializedUser.HomeAddress?.City); // 输出:深圳市
2.2.2 Newtonsoft.Json
复制代码
using Newtonsoft.Json;

// 1. 相同测试对象(同上)

var user = new User { /\* 初始化代码同上 \*/ };

// 2. 序列化(默认配置)

string jsonStr = JsonConvert.SerializeObject(user);

// 输出结果(默认格式化:紧凑模式,日期为本地时间字符串格式)

// {"Id":1,"Name":"张三","RegisterTime":"2024-05-01 10:30:00","Balance":100.50,"HomeAddress":{"Province":"广东省","City":"深圳市"}}

// 3. 反序列化

User deserializedUser = JsonConvert.DeserializeObject\<User>(jsonStr)!;

Console.WriteLine(deserializedUser.HomeAddress?.City); // 输出:深圳市
基本用法核心差异:
特性 System.Text.Json Newtonsoft.Json
核心静态类 JsonSerializer JsonConvert
默认日期格式 ISO 8601(如2024-05-01T10:30:00 本地时间字符串(如2024-05-01 10:30:00
空值属性处理 默认序列化(需配置IgnoreNullValues隐藏) 默认序列化(需配置NullValueHandling.Ignore隐藏)
缩进格式化 需指定JsonSerializerOptions { WriteIndented = true } 需指定Formatting.Indented

2.3 高级配置场景对比

2.3.1 场景 1:自定义日期格式
System.Text.Json
复制代码
var options = new JsonSerializerOptions

{

   WriteIndented = true, // 缩进格式化

   Converters = { new JsonStringEnumConverter() }, // 枚举转字符串(若有枚举类型)

   DateFormatString = "yyyy-MM-dd HH:mm:ss" // 自定义日期格式

};

string jsonStr = JsonSerializer.Serialize(user, options);

// 日期输出:"RegisterTime":"2024-05-01 10:30:00"
Newtonsoft.Json
复制代码
var settings = new JsonSerializerSettings

{

   Formatting = Formatting.Indented, // 缩进格式化

   DateFormatString = "yyyy-MM-dd HH:mm:ss", // 自定义日期格式

   Converters = { new StringEnumConverter() } // 枚举转字符串

};

string jsonStr = JsonConvert.SerializeObject(user, settings);

// 日期输出:"RegisterTime":"2024-05-01 10:30:00"
2.3.2 场景 2:处理循环引用

假设user.Friend = user(自引用循环),默认配置下两者行为不同:

System.Text.Json

默认抛出JsonException(不支持循环引用),需手动配置忽略循环引用:

复制代码
var options = new JsonSerializerOptions

{

   ReferenceHandler = ReferenceHandler.IgnoreCycles, // 忽略循环引用

   WriteIndented = true

};

string jsonStr = JsonSerializer.Serialize(user, options);

// 循环引用属性(Friend)会被序列化为null
Newtonsoft.Json

默认抛出JsonSerializationException,但支持多种循环引用策略:

复制代码
var settings = new JsonSerializerSettings

{

   Formatting = Formatting.Indented,

   // 选项1:忽略循环引用(设为null)

   ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

   // 选项2:保留循环引用(通过\$ref/\$id标记)

   // ReferenceLoopHandling = ReferenceLoopHandling.Serialize,

   // PreserveReferencesHandling = PreserveReferencesHandling.Objects

};

string jsonStr = JsonConvert.SerializeObject(user, settings);

// 选项1输出:Friend属性为null;选项2输出:包含\$ref:"#"标记
2.3.3 场景 3:忽略空值属性
System.Text.Json
复制代码
var options = new JsonSerializerOptions

{

   IgnoreNullValues = true, // .NET 6+推荐用IgnoreNullValues(替代旧版IgnoreNulls)

   WriteIndented = true

};

// 若HomeAddress为null,序列化后会隐藏该属性
Newtonsoft.Json
复制代码
var settings = new JsonSerializerSettings

{

   NullValueHandling = NullValueHandling.Ignore,

   Formatting = Formatting.Indented

};

// 空值属性会被隐藏

2.4 特殊类型处理对比

2.4.1 DataTable 序列化

Newtonsoft.Json 原生支持DataTable,System.Text.Json 需自定义转换器:

Newtonsoft.Json(原生支持)
复制代码
var dt = new DataTable("UserTable");

dt.Columns.Add("Id", typeof(int));

dt.Columns.Add("Name", typeof(string));

dt.Rows.Add(1, "张三");

dt.Rows.Add(2, "李四");

string json = JsonConvert.SerializeObject(dt, Formatting.Indented);

// 输出包含"TableName":"UserTable"、"Columns"、"Rows"的结构化JSON
System.Text.Json(需自定义转换器)
复制代码
// 1. 定义DataTable转换器(简化版)

public class DataTableConverter : JsonConverter\<DataTable>

{

   public override DataTable Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

   {

       // 反序列化逻辑(略,需解析Columns和Rows)

       throw new NotImplementedException();

   }

   public override void Write(Utf8JsonWriter writer, DataTable value, JsonSerializerOptions options)

   {

       writer.WriteStartObject();

       writer.WriteString("TableName", value.TableName);

      

       // 序列化Columns

       writer.WriteStartArray("Columns");

       foreach (DataColumn col in value.Columns)

       {

           writer.WriteStartObject();

           writer.WriteString("ColumnName", col.ColumnName);

           writer.WriteString("DataType", col.DataType.Name);

           writer.WriteEndObject();

       }

       writer.WriteEndArray();

       // 序列化Rows

       writer.WriteStartArray("Rows");

       foreach (DataRow row in value.Rows)

       {

           writer.WriteStartArray();

           foreach (var val in row.ItemArray)

           {

               JsonSerializer.Serialize(writer, val, options);

           }

           writer.WriteEndArray();

       }

       writer.WriteEndArray();

      

       writer.WriteEndObject();

   }

}

// 2. 使用转换器

var options = new JsonSerializerOptions

{

   WriteIndented = true,

   Converters = { new DataTableConverter() }

};

string json = JsonSerializer.Serialize(dt, options);

// 输出与Newtonsoft类似的结构化JSON

三、性能对比:谁更快、更省内存?

性能是选择 JSON 库的核心考量因素之一。我们基于.NET 8 环境,通过BenchmarkDotNet对 "简单对象""复杂对象""大集合" 三类场景进行测试,对比两者的序列化 / 反序列化速度与内存占用。

3.1 测试环境

  • 框架:.NET 8.0

  • CPU:Intel Core i7-12700H(14 核 20 线程)

  • 内存:32GB DDR5 4800MHz

  • 测试工具:BenchmarkDotNet 0.13.12

3.2 测试场景与结果

场景 1:简单对象(User 类,无嵌套)
操作 平均耗时(ns) 内存分配(B / 次) 吞吐量(次 / 秒)
序列化 System.Text.Json 385 192 2,597,403
序列化 Newtonsoft.Json 892 480 1,121,075
反序列化 System.Text.Json 456 224 2,192,982
反序列化 Newtonsoft.Json 987 544 1,013,172
场景 2:复杂对象(User 类 + 嵌套 3 层 Address+List)
操作 平均耗时(ns) 内存分配(B / 次) 吞吐量(次 / 秒)
序列化 System.Text.Json 1,245 640 803,214
序列化 Newtonsoft.Json 2,876 1,536 347,692
反序列化 System.Text.Json 1,582 768 632,111
反序列化 Newtonsoft.Json 3,218 1,856 310,752
场景 3:大集合(1000 个 User 对象的 List)
操作 平均耗时(μs) 内存分配(KB / 次) 吞吐量(次 / 秒)
序列化 System.Text.Json 386 128 2,590
序列化 Newtonsoft.Json 924 352 1,082
反序列化 System.Text.Json 458 192 2,183
反序列化 Newtonsoft.Json 1,056 480 947

3.3 性能差异核心原因

  1. 内存操作方式
  • System.Text.Json 基于Span<T>直接操作 UTF-8 字节流,避免字符串与字节流的转换开销,内存分配仅为 Newtonsoft 的 1/3~1/2;

  • Newtonsoft.Json 基于字符串处理,需多次创建中间字符串对象,GC 压力更大。

  1. 序列化逻辑优化
  • System.Text.Json 采用 "预编译契约"(提前解析对象属性信息),减少反射开销;

  • Newtonsoft.Json 依赖运行时反射,且支持更多复杂特性(如动态类型),逻辑更重。

  1. 兼容性 trade-off
  • System.Text.Json 默认遵循严格 JSON 规范,减少了非标准场景的分支判断;

  • Newtonsoft.Json 需处理大量非标准 JSON 和特殊类型,逻辑分支更多,耗时更长。

四、适用场景选型建议

通过前文对比,两者的适用场景有明确区分,需结合项目需求选择:

4.1 优先选择 System.Text.Json 的场景

  1. 新开发的.NET Core/.NET 5 + 项目
  • 尤其是ASP.NET Core API 项目,默认集成无需额外安装,配置更简单;

  • 需 AOT 编译的场景(如 Blazor WASM、Native AOT 桌面应用),Newtonsoft 存在兼容性问题。

  1. 高性能要求场景
  • 高频序列化 / 反序列化(如 API 网关、缓存服务);

  • 大流量系统(如电商秒杀、日志收集),需降低内存占用和 GC 压力。

  1. 标准 JSON 格式场景
  • 仅处理 RFC 8259 标准 JSON,无需非标准特性(如注释、单引号);

  • 无需支持DataSetExpandoObject等特殊类型。

4.2 优先选择 Newtonsoft.Json 的场景

  1. 旧项目迁移 / 兼容场景
  • .NET Framework 项目或已依赖 Newtonsoft 的.NET Core 项目,避免重构成本;

  • 第三方库强制依赖 Newtonsoft(如部分 ORM、Swagger 插件)。

  1. 复杂 JSON 处理场景
  • 需处理非标准 JSON(如带注释的配置文件、单引号 JSON);

  • 需支持循环引用、DataSetDynamicObject等特殊类型;

  • 需自定义复杂序列化逻辑(如属性名动态映射、条件序列化)。

  1. 快速开发场景
  • 项目周期短,需利用 Newtonsoft 丰富的文档和社区资源;

  • 团队更熟悉 Newtonsoft API,无需学习新库的配置方式。

五、其他常用 JSON 序列化库

除了上述两款主流库,.NET 生态中还有几款针对特定场景优化的 JSON 库,可根据需求选择:

5.1 Utf8Json(由 neuecc 开发)

  • 核心特点 :基于Span<T>的超高性能库,性能略优于 System.Text.Json,内存分配极低;

  • 优势:支持匿名对象、动态类型,配置简单;

  • 劣势:维护频率较低(最新版本 2022 年更新),生态兼容性一般;

  • 适用场景:对性能要求极致的场景(如高频交易系统)。

  • 安装Install-Package Utf8Json

5.2 Jil(由 Kevin Montrose 开发)

  • 核心特点:轻量级高性能库,设计目标是 "最快的.NET JSON 库之一";

  • 优势:API 简洁,支持自定义转换器,内存占用低;

  • 劣势:不支持循环引用,复杂类型处理能力弱;

  • 适用场景:简单对象的快速序列化 / 反序列化(如日志序列化)。

  • 安装Install-Package Jil

5.3 MessagePack-CSharp(微软官方维护)

  • 核心特点:基于 MessagePack 格式(二进制 JSON),体积比 JSON 小 30%~50%;

  • 优势:支持 UTF-8、AOT 编译,与 System.Text.Json API 相似,适合网络传输;

  • 劣势:非文本格式,可读性差,需两端均支持 MessagePack;

  • 适用场景:分布式系统间二进制数据传输(如微服务调用)。

  • 安装Install-Package MessagePack

5.4 ServiceStack.Text(ServiceStack 生态组件)

  • 核心特点:ServiceStack 框架的一部分,支持 JSON、CSV、JSV 等多种格式;

  • 优势:高性能,支持 "无反射" 序列化,与 ServiceStack 生态深度集成;

  • 劣势:需依赖 ServiceStack 核心库,单独使用成本高;

  • 适用场景:使用 ServiceStack 框架的项目(如旧版 ServiceStack API)。

  • 安装Install-Package ServiceStack.Text

六、总结

System.Text.Json 与 Newtonsoft.Json 并非 "替代关系",而是 "互补关系":

  • 若你追求性能、轻量、标准兼容且项目基于.NET Core 3.0+,优先选择 System.Text.Json;

  • 若你需要复杂特性、生态兼容、旧项目支持,优先选择 Newtonsoft.Json。

在实际开发中,还可根据场景混合使用(如ASP.NET Core API 用 System.Text.Json,配置文件解析用 Newtonsoft)。此外,若对性能或体积有极致要求,可考虑 Utf8Json 或 MessagePack-CSharp 等专用库。

技术选型的核心是 "匹配项目需求",而非盲目追求 "最新" 或 "最快"------ 合适的才是最好的。

相关推荐
mpHH2 小时前
postgresql中的默认列
数据库·postgresql
csdn_aspnet2 小时前
ASP.NET Core 10.0 的主要变化
.netcore
jllws12 小时前
数据库原理及应用_数据库基础_第4章关系模型的基本理论_数据库完整性规则和MySQL提供的约束
数据库
majunssz4 小时前
深入剖析Spring Boot依赖注入顺序:从原理到实战
java·数据库·spring boot
比特森林探险记5 小时前
MySQL 架构全景解析
数据库·mysql·架构
数字冰雹5 小时前
图观 流渲染场景服务器
服务器·前端·数据库·数据可视化
千叶寻-5 小时前
package.json详解
前端·vue.js·react.js·webpack·前端框架·node.js·json
pccai-vip5 小时前
系分论文《论非关系型数据库(NoSQL)在社交媒体内容管理系统中的应用》
数据库·nosql·媒体
谱写秋天5 小时前
软考-系统架构设计师 NoSQL数据库详细讲解
数据库·系统架构·软考架构师