.NET的JSON序列化与反序列化-System.Text.Json精讲🚀🚀

496 阅读4分钟

Json的序列化与反序列化(System.Text.Json)大家都会用,但是大家都会用得比较模糊,本文通过详细的讲解使大家清晰的讲握System.Text.Json的使用,因为...“清晰”是知识真正被学习和掌握的标志😊.

为什么一定是System.Text.Json😊 ?

.NET中有很多好的开源Json解析框架,如: Newtonsoft.Json,为什么一定要使用System.Text.Json?
因为:

  • 微软的官方包,它在.NET Core 3.0及更高版本中提供了内置支持,微软官方代码都是使用System.Text.Json,了解它很重要!
  • 性能表现优秀,官方讲的是:高性能和低内存分配!
  • 多线程安全性;

术语解释:
序列化:把对象变成字符串,即:Object--> string
反序列化: 把字符串转成对象,即: string--> Object

涉及的命名空间 🚀🚀

  • System.Text.Json: 最主要提供了序列化与反序列化的核心类:如JsonSerializer等;
  • System.Text.Json.Serialization: 提供象[JsonPropertyName]等特性、JsonSerializerOptions的扩展的支持;
  • System.Net.Http.Json: 给HttpClient类使用,在进行Http访问时将返回的内容进行反序列化,这个在使用HttpClient的时会提供极大的方便;

基本使用(序列化/反序列化) 🎉🎉

  • 序列化

使用JsonSerializer.Serialize()或者重载的使用JsonSerializer.Serialize版本,System.Text.Json为也提供异步版本

using demo;
using System.Text.Json;
using System.Text.Json.Serialization;

var persion = new Person("John Doe", 30,true, new DateTime(1993, 5, 15));

var jsonString = JsonSerializer.Serialize(persion);
var jsonString2 = JsonSerializer.Serialize<Person>(persion);

Console.WriteLine(jsonString);
Console.WriteLine(jsonString2);

//output: {"Name":"John Doe","Age":30,"IsStudent":true,"Birthday":"1993-05-15T00:00:00"}

注意这里的输出: 默认情况下,JSON 输出会被缩小(将删除空格、缩进和换行符),如果在日志的场合,这个不好观察日志输出,下面论述中的JsonSerializerOptions类可以使输出更容易观测,详见下面的论述。

  • 反序列化

使用JsonSerializer.Deserialize()或者重载的使用JsonSerializer.Deserialize版本,System.Text.Json为也提供异步版本供反序列化;

using demo;
using System.Text.Json;
using System.Text.Json.Serialization;


var jsonString = """
    {"Date":"2025-06-23T01:11:58.4217508+08:00","TemperatureCelsius":25,"Summary":"Sunny","Wind":10}
""";
var jsonObject = JsonSerializer.Deserialize<WeatherForecast>(jsonString);

Console.WriteLine(jsonObject?.Date);
Console.WriteLine(jsonObject?.TemperatureCelsius);
Console.WriteLine(jsonObject?.Summary);
Console.WriteLine(jsonObject?.WindSpeed);

对序列化/反序列化行为的控制 🚀🚀

何谓"行为控制"?😂

例如:我们在进行前后端开发的时候,前端的对象的字段一般为驼峰命名,而我们在后端用C#写程序用的是Pascal命名法,所以我们需要转换属性名,这个就需要对序列化/反序列化行为进行控制;

例如:System.Text.Json默认只对公开的属性进行序列化/反序列化,而默认不会对字段进行序列化/反序列化,这个时候,我们也需要对序列化/反序列化的行为进行控制;

有两种对序列化/反序列化行为的控制方法:

  • 使用特性[JsonPropertyName]、[JsonIgnore]、[JsonInclude]等
  • 使用JsonSerializerOptions类

注1:使用特性与JsonSerializerOptions类都能对序列化/反序列化的行为进行控制,但是特性更多应用在单个类、单个字段,而JsonSerializerOptions类更多用于全局控制及实际很多特性无法完成的json实例化/反实例化控制,所以下面最主要介绍JsonSerializerOptions类

注2: 特性的权重更高,意味着如果同时设置了特性并同时也受JsonSerializerOptions的约束,那么特性的权重更高,会覆盖JsonSerializerOptions的设置

JsonSerializerOptions

  • 自定义属性名
using demo;
using System.Text.Json;
using System.Text.Json.Serialization;

var weather = new WeatherForecast()
{
    Date = DateTimeOffset.Now,
    TemperatureCelsius = 25,
    Summary = "Sunny",
    WindSpeed = 10
};


var jsonoptions = new JsonSerializerOptions
{
   PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};

var json = JsonSerializer.Serialize(weather, jsonoptions);
Console.WriteLine(json);

输出是:

{"date":"2025-06-23T02:04:44.6282091+08:00","temperatureCelsius":25,"summary":"Sunny","Wind":10}

所有字段名变成web的驼峰命名😊

内置可选的命名策略:(基本上够用,也可以自定义)

命名策略说明原始属性名称经过转换的属性名称
CamelCase第一个单词以小写字符开头。 连续单词以大写字符开头。TempCelsiustempCelsius
KebabCaseLower*单词由连字符分隔。 所有字符均为小写。TempCelsiustemp-celsius
KebabCaseUpper*单词由连字符分隔。 所有字符均为大写。TempCelsiusTEMP-CELSIUS
SnakeCaseLower*单词用下划线分隔。 所有字符均为小写。TempCelsiustemp_celsius
SnakeCaseUpper*单词用下划线分隔。 所有字符均为大写。TempCelsiusTEMP_CELSIUS
  • 输出人类更友好格式
using demo;
using System.Text.Json;
using System.Text.Json.Serialization;

var weather = new WeatherForecast()
{
    Date = DateTimeOffset.Now,
    TemperatureCelsius = 25,
    Summary = "Sunny",
    WindSpeed = 10
};


var jsonoptions = new JsonSerializerOptions
{
    WriteIndented = true
};

var json = JsonSerializer.Serialize(weather, jsonoptions);
Console.WriteLine(json);

输出:

{
  "Date": "2025-06-23T02:10:26.5399846+08:00",
  "TemperatureCelsius": 25,
  "Summary": "Sunny",
  "Wind": 10
}

而不是:

{"Date":"2025-06-23T02:12:01.0235206+08:00","TemperatureCelsius":25,"Summary":"Sunny","Wind":10}

用在控制台或者日志输出中使人更可读'

  • 忽略属性:即不参与序列化与反序列化
public class WeatherForecastWithIgnoreAttribute
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    [JsonIgnore]
    public string? Summary { get; set; }
}

输出:

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
   //缺失了Summary
}
  • 包含字段

默认情况下,字段不会序列化,默认序列化与反序列化属性

//1. 使用特性的方式
public class Forecast2
{
    [JsonInclude]
    public DateTime Date;
    [JsonInclude]
    public int TemperatureC;
    [JsonInclude]
    public string? Summary;
}
//2. 使用JsonSerializerOptions.IncludeFields全局设置

拓展学习🎉🎉

更多的请参见微软的官方文档:
.NET中的JSON序列化和反序列化