欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > C# System.Text.Json 中 JsonConverter 使用详解

C# System.Text.Json 中 JsonConverter 使用详解

2025/4/17 13:38:17 来源:https://blog.csdn.net/qq_39847278/article/details/146957465  浏览:    关键词:C# System.Text.Json 中 JsonConverter 使用详解

总目录


前言

在 C# 开发中,System.Text.Json 是一个高性能的 JSON 处理库,广泛用于序列化和反序列化对象。当默认的序列化行为无法满足需求时,JsonConverter 提供了强大的自定义能力。本文将详细讲解 JsonConverter 的使用方法,帮助你灵活处理复杂的 JSON 数据。


一、 JsonConverter 是什么?

1. 概述

JsonConverterSystem.Text.Json.Serialization 命名空间中的一个抽象类,它提供了将对象或值转换为 JSON 格式以及将 JSON 格式转换回对象或值的功能。System.Text.Json 提供了内置的 JsonConverter 实现,用于处理大多数基本类型,同时开发者也可以通过实现 JsonConverter<T>创建自定义的 JsonConverter 来满足特定需求。

JsonConverterSystem.Text.Json 中用于 自定义序列化和反序列化逻辑的核心类。它允许开发者完全控制 .NET 对象与 JSON 格式之间的转换过程,

2. 为什么需要 JsonConverter?

默认的序列化行为可能无法满足以下需求:

  • 特殊数据格式:日期、货币、自定义对象,如日期需格式化为 yyyy-MM-dd HH:mm:ss
  • 非标准 JSON 结构:如将嵌套对象转换为扁平化 JSON。
  • 安全处理:过滤敏感字段或转换加密数据。
  • 性能优化:避免反射或减少内存分配。

通过继承 JsonConverter<T>,开发者可以完全控制类型与 JSON 之间的转换过程。

3. JsonConverter 核心原理

JsonConverter<T> 是一个泛型类,要求实现以下两个关键方法:

  1. Read:从 Utf8JsonReader 中读取 JSON 数据并转换为 .NET 对象。
  2. Write:将 .NET 对象写入 Utf8JsonWriter 生成 JSON。

代码示例:

public class CustomConverter : JsonConverter<CustomType>
{public override CustomType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){// 实现反序列化逻辑}public override void Write(Utf8JsonWriter writer, CustomType value, JsonSerializerOptions options){// 实现序列化逻辑}
}

二、使用

1. 内置 JsonConverter

1)内置 JsonConverter 介绍

▶ 内置转换器

System.Text.Json 为映射到 JavaScript 基元的大多数基本类型提供了内置转换器。这些内置转换器可以处理以下基本类型:字符串、整数、浮点数、布尔值、数组和集合、字典、日期和时间(ISO 8601 格式)。

对于日期和时间类型,System.Text.Json 实现了 ISO 8601-1:2019 扩展配置文件,定义了日期和时间表示形式的组件。
详见:System.Text.Json 中的 DateTime 和 DateTimeOffset 支持。

▶ 使用内置 JsonConverter

System.Text.Json 提供的内置转换器可以处理大多数常见类型,无需额外配置即可使用。以下是一个简单的使用示例:

public class Person
{public string Name { get; set; }public int Age { get; set; }public DateTime BirthDate { get; set; }
}
class Program
{static void Main(){// 使用内置转换器序列化对象var person = new Person{Name = "John Doe",Age = 30,BirthDate = new DateTime(1990, 1, 1)};string json = JsonSerializer.Serialize(person);Console.WriteLine(json);// 输出:{"Name":"John Doe","Age":30,"BirthDate":"1990-01-01T00:00:00"}}
}

在上述示例中,System.Text.Json 使用内置转换器自动处理了 Person 对象的所有属性,包括 DateTime 类型的 BirthDate 属性,以 ISO 8601 格式进行序列化。

2)内置转换器:JsonStringEnumConverter

JsonStringEnumConverterSystem.Text.Json 中用于 将枚举(Enum)类型序列化为字符串,并支持从字符串反序列化为枚举值的内置转换器。它是 JsonConverter 的一个特化实现,专门处理枚举类型,解决了默认序列化(将枚举值转为整数)的局限性。

▶ 通过JsonSerializerOptions全局使用

定义枚举类型和相关对象:

public enum Status { Active, Inactive, Pending }
public enum CountryType { China, USA,Japan }public class Order
{public int Id { get; set; }public string Name { get; set; }public CountryType CountryType { get; set; }public Status Status { get; set; }
}

默认枚举会序列化为整数,使用 JsonStringEnumConverter 可转为字符串:

class Program
{static void Main(){// 正常序列化var order = new Order { Id = 1, Name = "Order0001", CountryType = CountryType.China, Status = Status.Pending };string json = JsonSerializer.Serialize(order);Console.WriteLine(json);// 输出:{"Id":1,"Name":"Order0001","CountryType":0,"Status":2}// 方式1var options = new JsonSerializerOptions{Converters = { new JsonStringEnumConverter() }};json = JsonSerializer.Serialize(order, options);Console.WriteLine(json);// 输出:{"Id":1,"Name":"Order0001","CountryType":"China","Status":"Pending"}// 方式2var options2 = new JsonSerializerOptions();options2.Converters.Add(new JsonStringEnumConverter());json = JsonSerializer.Serialize(order, options);Console.WriteLine(json);// 输出:{"Id":1,"Name":"Order0001","CountryType":"China","Status":"Pending"}}
}
▶ 针对特定枚举类型

如下例中通过JsonSerializerOptions中的Converters 配置只针对 Status 枚举的转换

var options = new JsonSerializerOptions
{Converters = { new JsonStringEnumConverter<Status>() }
};
json = JsonSerializer.Serialize(order, options);
Console.WriteLine(json);
// 输出:{"Id":1,"Name":"Order0001","CountryType":0,"Status":"Pending"}
▶ 通过JsonConverter 特性使用

直接在枚举类型上使用 [JsonConverter] 特性,适用于指定特定属性使用

// 第一种方式:直接在枚举上添加特性
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Status{ Active, Inactive, Pending}
public enum CountryType{China, USA,Japan}public class Order
{public int Id { get; set; }public string Name { get; set; }// 第二种方式:在对象相关属性上添加特性[JsonConverter(typeof(JsonStringEnumConverter))]public CountryType CountryType { get; set; }public Status Status { get; set; }
}
class Program
{static void Main(){// 正常序列化var order = new Order { Id = 1, Name = "Order0001", CountryType = CountryType.China, Status = Status.Pending };string json = JsonSerializer.Serialize(order);Console.WriteLine(json);// 输出:{"Id":1,"Name":"Order0001","CountryType":"China","Status":"Pending"}}
}
▶ 配置JsonStringEnumConverter 的命名策略

可通过 JsonNamingPolicy 自定义枚举值的输出格式(如 CamelCase、PascalCase 等)。

public enum Status{ Active, Inactive, Pending}
public enum CountryType{China, USA,Japan}public class Order
{public int Id { get; set; }public string Name { get; set; }   public CountryType CountryType { get; set; }public Status Status { get; set; }
}
class Program
{static void Main(){// 正常序列化var order = new Order { Id = 1, Name = "Order0001", CountryType = CountryType.China, Status = Status.Pending };var options = new JsonSerializerOptions() { Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)  }};string json = JsonSerializer.Serialize(order,options);Console.WriteLine(json);// 输出:{"Id":1,"Name":"Order0001","CountryType":"china","Status":"pending"}}
}

2. 自定义 JsonConverter

当内置转换器无法满足需求时,开发者可以创建自定义的 JsonConverter。自定义转换器需要继承 JsonConverter 类并实现两个主要方法:Read 和 Write。

下面 将通过 将日期序列化为 yyyy-MM-dd 的案例来说明如何自定义 JsonConverter

1)创建自定义转换器

创建自定义转换器类,继承 JsonConverter<T>

public class DateFormatterConverter : JsonConverter<DateTime>
{public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){// 实现 反序列化逻辑:将Json 转化为 .NET对象}public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options){// 实现 序列化逻辑:将 .NET对象 转化为Json}
}

2)实现 ReadWrite 方法

public class DateFormatterConverter : JsonConverter<DateTime>
{public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){return DateTime.Parse(reader.GetString()!);}public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString("yyyy-MM-dd"));}
}

3)使用自定义JsonConverter

▶ 通过JsonSerializerOptions全局使用
public class Person
{public string Name { get; set; }public int Age { get; set; }public DateTime BirthDate { get; set; }
}class Program
{static void Main(){var person = new Person{Name = "John Doe",Age = 30,BirthDate = new DateTime(1990, 1, 1)};var options = new JsonSerializerOptions() { Converters = { new DateFormatterConverter()  }};string json = JsonSerializer.Serialize(person, options);Console.WriteLine(json);// 输出:{"Name":"John Doe","Age":30,"BirthDate":"1990-01-01"}}
}
▶ 通过JsonConverter 特性使用
public class Person
{public string Name { get; set; }public int Age { get; set; }[JsonConverter(typeof(DateFormatterConverter))]public DateTime BirthDate { get; set; }
}class Program
{static void Main(){var person = new Person{Name = "John Doe",Age = 30,BirthDate = new DateTime(1990, 1, 1)};string json = JsonSerializer.Serialize(person);Console.WriteLine(json);// 输出:{"Name":"John Doe","Age":30,"BirthDate":"1990-01-01"}}
}

三、实战案例

1. 自定义日期格式

1)创建自定义转换器类

System.Text.Json 默认使用 ISO 8601 格式序列化日期。如果需要自定义日期格式,可以创建一个处理 DateTime 的自定义转换器:

public class CustomDateTimeConverter : JsonConverter<DateTime>
{private readonly string _format;public CustomDateTimeConverter(string format){_format = format;}public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){if (reader.TokenType == JsonTokenType.String){return DateTime.ParseExact(reader.GetString()!, _format, System.Globalization.CultureInfo.InvariantCulture);}throw new JsonException();}public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString(_format));}
}

2)使用自定义转换器

class Program
{static void Main(){// 使用自定义日期格式var options = new JsonSerializerOptions{Converters = { new CustomDateTimeConverter("yyyy-MM-dd") }};var person = new{Name = "John Doe",Age = 30,BirthDate = new DateTime(1990, 1, 1)};string json = JsonSerializer.Serialize(person,options);Console.WriteLine(json);// 输出:{"Name":"John Doe","Age":30,"BirthDate":"1990-01-01"}var options2 = new JsonSerializerOptions();options2.Converters.Add(new CustomDateTimeConverter("yyyy-MM-dd HH:mm:ss"));json = JsonSerializer.Serialize(person,options2);Console.WriteLine(json);// 输出:{"Name":"John Doe","Age":30,"BirthDate":"1990-01-01 00:00:00"}}
}

在这个示例中,StringEnumConverter 用于将 DayOfWeek 枚举转换为字符串。Read 方法将 JSON 字符串解析为 DayOfWeek 枚举值,Write 方法将 DayOfWeek 枚举值写为 JSON 字符串。

2. 自定义枚举格式

如果需要自定义枚举的序列化行为,可以创建自己的转换器:

public class CustomEnumConverter : JsonConverter<DayOfWeek>
{public override DayOfWeek Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options){string dayString = reader.GetString();if (Enum.TryParse(dayString, out DayOfWeek day)){return day;}throw new JsonException("Invalid day of week.");}public override void Write(Utf8JsonWriter writer, DayOfWeek value, JsonSerializerOptions options){writer.WriteStringValue(value.ToString());}
}

3. 将对象转换为扁平化 JSON

需求:将嵌套对象扁平化为 JSON。

public class Address
{public string City { get; set; }public string ZipCode { get; set; }
}public class User
{public string Name { get; set; }public Address Address { get; set; }
}// 自定义转换器
public class UserConverter : JsonConverter<User>
{public override User Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){var user = new User();while (reader.Read()){if (reader.TokenType == JsonTokenType.EndObject)return user;if (reader.TokenType == JsonTokenType.PropertyName){var propName = reader.GetString();reader.Read();switch (propName.ToLower()){case "name":user.Name = reader.GetString();break;case "city":user.Address ??= new Address();user.Address.City = reader.GetString();break;case "zip":user.Address ??= new Address();user.Address.ZipCode = reader.GetString();break;}}}throw new JsonException("Unexpected JSON structure");}public override void Write(Utf8JsonWriter writer, User user, JsonSerializerOptions options){writer.WriteStartObject();writer.WriteString("name", user.Name);if (user.Address != null){writer.WriteString("city", user.Address.City);writer.WriteString("zip", user.Address.ZipCode);}writer.WriteEndObject();}
}

使用示例:

class Program
{static void Main(){var user = new User { Name = "Alice", Address = new Address { City = "Beijing", ZipCode = "100000" } };// 序列化string json = JsonSerializer.Serialize(user); Console.WriteLine(json);// 输出:{"Name":"Alice","Address":{"City":"Beijing","ZipCode":"100000"}}// 序列化:扁平化JSON var options = new JsonSerializerOptions { Converters = { new UserConverter() } };json = JsonSerializer.Serialize(user, options); Console.WriteLine(json);// 输出:{"name":"Alice","city":"Beijing","zip":"100000"}// 反序列化:扁平化JSON string jsonString = """{"name":"Alice","city":"Beijing","zip":"100000"}""";var user2= JsonSerializer.Deserialize<User>(jsonString,options);Console.WriteLine($"Name = {user2.Name} , City = {user2.Address.City} , ZipCode = {user2.Address.ZipCode}");// 输出:Name = Alice , City = Beijing , ZipCode = 100000}
}

4. 过滤敏感字段

需求:序列化时忽略敏感字段(如密码)。

public class User
{public string Name { get; set; }public string Password { get; set; } // 需要忽略的字段
}public class SecureUserConverter : JsonConverter<User>
{public override User Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options){// 反序列化逻辑(略)throw new NotImplementedException();}public override void Write(Utf8JsonWriter writer, User user, JsonSerializerOptions options){writer.WriteStartObject();writer.WriteString("name", user.Name);// 跳过 Password 字段writer.WriteEndObject();}
}

📌 关于以上案例中,自定义JsonConverter 里的Read 和 Write 方法所涉及的Utf8JsonReader 与Utf8JsonWriter 对象的详细内容,可见:C# Utf8JsonReader 和 Utf8JsonWriter 使用详解

四、性能优化技巧

1. 避免反射

直接操作 Utf8JsonReaderUtf8JsonWriter,减少对象创建:

public override void Write(Utf8JsonWriter writer, MyType value, JsonSerializerOptions options)
{writer.WriteStartObject();writer.WriteString("key", value.Property); // 直接写入属性writer.WriteEndObject();
}

2. 缓存转换器实例

private static readonly DateFormatterConverter _dateConverter = new DateFormatterConverter();
var options = new JsonSerializerOptions { Converters = { _dateConverter } };

五、异常处理与调试

1. 捕获反序列化错误

public override User Read(ref Utf8JsonReader reader, Type type, JsonSerializerOptions options)
{try{// 反序列化逻辑}catch (Exception ex){throw new JsonException("Failed to parse user data", ex);}
}

2. 日志记录与调试

ReadWrite 方法中添加日志输出:

Console.WriteLine($"Serializing {value.Name} to JSON");

结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:

  • 如何在 .NET 中编写用于 JSON 序列化(封送)的自定义转换器
  • .NET 官方文档:System.Text.Json
  • JsonConverter 源码分析

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词