开发者

.NET中自定义JSON转换器的实战指南

目录
  • 一、为什么需要自定义 jsON 转换器?
  • 二、基本模式:实现 JsonConverter<T>
    • 2.1 适用场景
    • 2.2 核心方法
    • 2.3 实战案例:日期格式自定义转换器
      • 场景需求
      • 使用示例
      • 技术细节
  • 三、工厂模式:处理开放式泛型类型
    • 3.1 适用场景
      • 3.2 核心方法
        • 3.3 实战案例:泛型集合转换器
          • 场景需求
          • 代码实现
          • 使用示例
          • 技术细节
      • 四、性能优化技巧
        • 4.1 避免频繁创建对象
          • 4.2 使用高性能 API
            • 4.3 内存优化
            • 五、高级场景:科学计数法转字符串
              • 5.1 问题描述
                • 5.2 解决方案
                  • 绑定模型
              • 六、常见陷阱与解决方案
                • 6.1 CanConvert 方法误判
                  • 6.2 嵌套类型处理失败
                    • 6.3 线程安全问题
                    • 七、自定义转换器的设计哲学
                      • 代码模板
                        • 基本模式模板
                          • 工厂模式模板

                          一、为什么需要自定义 JSON 转换器?

                          在 .NET 开发中,JSON 序列化与反序列化是日常开发的核心操作。然而,标准的序列化器(如 Sysjavascripttem.Text.Json)并不能满足所有场景需求。以下是常见的痛点:

                          1. 数据格式不兼容
                            • 例如:前端要求日期格式为 "yyyy-MM-dd",而默认格式为 ISO 8601。
                          2. 复杂类型处理
                            • 例如:枚举类型需要自定义映射规则(如 Enumstring 而非 int)。
                          3. 性能瓶颈
                            • 例如:需要避免频繁创建临时对象或优化内存分配。
                          4. 特殊业务逻辑
                            • 例如:将数据库中的科学计数法字段(1.23E+08)转为正常数字格式。

                          自定义 JSON 转换器JsonConverter<T>)正是解决这些问题的利器。本文将通过 基本模式工厂模式 的实战案例,带你掌握自定义转换器的核心技巧。

                          二、基本模式:实现 JsonConverter<T>

                          2.1 适用场景

                          • 非泛型类型封闭式泛型类型(如 List<DateTime>Dictionary<string, int>)。
                          • 需要控制特定类型的序列化/反序列化逻辑。

                          2.2 核心方法

                          • Read:将 JSON 反序列化为 .NET 对象。
                          • Write:将 .NET 对象序列化为 JSON。
                          • CanConvert(可选):判断是否支持该类型。

                          2.3 实战案例:日期格式自定义转换器

                          场景需求

                          • 目标:将 DateTime 字段从默认的 ISO 8601 格式("2025-07-19T17:11:39Z")转为 "yyyy-MM-dd" 格式。
                          • 代码实现
                          using System;
                          using System.Text.Json;
                          using System.Text.Json.Serialization;
                          
                          // 自定义 DateTime 转换器
                          public class CustomDateTimeConverter : JsonConverter<DateTime>
                          {
                              private const string DateFormat = "yyyy-MM-dd";
                          
                              // 反序列化:JSON -> DateTime
                              public override DateTime Read(
                                  ref Utf8JsonReader reader, 
                                  Twww.devze.comype typeToConvert, 
                                  JsonSerializerOptions options)
                              {
                                  // 处理 null 值
                                  if (reader.TokenType == JsonTokenType.Null)
                                      return default;
                          
                                  // 读取 JSON 字符串
                                  var dateString = reader.GetString();
                                  if (DateTime.TryParseExact(dateString, DateFormat, null, System.Globalization.DateTimeStyles.None, out var result))
                                  {
                                      return result;
                                  }
                          
                                  throw new JsonException($"Invalid date format. Expected '{DateFormat}' but got '{dateString}'");
                              }
                          
                              // 序列化:DateTime -> JSON
                              public override void Write(
                                  Utf8JsonWriter writer, 
                                  DateTime value, 
                                  JsonSerializerOptions options)
                              {
                                  // 格式化为指定格式
                                  writer.WriteStringValue(value.ToString(DateFormat));
                              }
                          }
                          

                          使用示例

                          public class Person
                          {
                              public string Name { get; set; }
                              [JsonConverter(typeof(CustomDateTimeConverter))] // 绑定转换器
                              public DateTime Birthday { get; set; }
                          }
                          
                          // 测试代码
                          var person = new Person 
                          { 
                              Name = "Alice", 
                              Birthday = new DateTime(2025, 7, 19) 
                          };
                          
                          var options = new JsonSerializerOptions
                          {
                              WriteIndented = true,
                              Converters = { new CustomDateTimeConverter() } // 注册全局转换器
                          };
                          
                          string json = JsonSerializer.Serialize(person, options);
                          Console.WriteLine(json); 
                          // 输出: {"Name":"Alice","Birthday":"2025-07-19"}
                          

                          技术细节

                          • Utf8JsonReader:高性能的 JSON 解析器,直接操作 UTF-8 缓冲区,避免字符串转换开销。
                          • Utf8JsonWriter:直接生成 UTF-8 字节流,减少中间字符串分配。
                          • 异常处理JsonException 是序列化框架的标准异常类型。

                          三、工厂模式:处理开放式泛型类型

                          3.1 适用场景

                          • 开放式泛型类型(如 List<T>Dictionary<TKey, TValue>)。
                          • 多态类型(如 Enum 或动态类型)。

                          3.2 核心方法

                          • CanConvert:判断是否支持当前类型。
                          • CreateConverter:动态创建特定类型的转换器实例。

                          3.3 实战案例:泛型集合转换器

                          场景需求

                          • 目标:支持任意 List<T> 类型的序列化,其中 T 可能是 intstring 或自定义类型。

                          代码实现

                          using System;
                          using System.Collections.Generic;
                          using System.Text.Json;
                          using System.Text.Json.Serialization;
                          
                          // 工厂类:处理 List<T>
                          public class ListConverterFactory : JsonConverterFactory
                          {
                              // 判断是否支持当前类型
                              public override bool CanConvert(Type typeToConvert)
                              {
                                  // 仅支持 List<T> 类型
                                  return typeToConvert.IsGenericType && 
                                         typeToConvert.GetGenericTypeDefinition() == typeof(List<>);
                              }
                          
                              // 动态创建转换器
                              public override JsonConverter CreateConverter(
                                  Type typeToConvert, 
                                  JsonSerializerOptions options)
                              {
                                  // 获取 T 的类型
                                  var genericType = typeToConvert.GetGenericArguments()[0];
                                  // 创建泛型转换器实例
                                  return (JsonConverter)Activator.CreateInstance(
                                      typeof(ListConverter<>).MakeGenericType(genericType));
                              }
                          }
                          
                          // 泛型转换器:处理 List<T>
                          public class ListConverter<T> : JsonConverter<List<T>>
                          {
                              // 反序列化:JSON -> List<T>
                              public override List<T> Read(
                                  ref Utf8JsonReader reader, 
                                  Type typeToConvert, 
                                  JsonSerializerOptions options)
                              {
                                  if (reader.TokenType != JsonTokenType.StartArray)
                                      throw new JsonException("Expected start of array");
                          
                                  var list = new List<T>();
                                  while (reader.Read())
                                  {
                                      if (reader.TokenType == JsonTokenType.EndArray)
                                          break;
                          
                                      var item = JsonSerializer.Deserialize<T>(ref reader, options);
                                      list.Add(item);
                                  }
                          
                                  return list;
                              }
                          
                              // 序列化:List<T> -> JSON
                              public override void Write(
                                  Utf8JsonWriter writer, 
                                  List<T> value, 
                                  JsonSerializerOptions options)
                              {
                                  writer.WriteStartArray();
                                  foreach (var item in value)
                                  {
                                      JsonSerializer.Serialize(writer, item, options);
                                  }
                                  writer.WriteEndArray();
                              }
                          }
                          

                          使用示例

                          public class Product
                          {
                              public string Name { get; set; }
                              public List&androidlt;int> Ratings { get; set; }
                          编程}
                          
                          // 注册工厂转换器
                          var options = new JsonSerializerOptions
                          {
                              WriteIndented = true,
                              Converters = { new ListConverterFactory() }
                          };
                          
                          var product = new Product
                          {
                              Name = "Laptop",
                              Ratings = new List<int> { 5, 4, 5 }
                          };
                          
                          string json = JsonSerializer.Serialize编程(product, options);
                          Console.WriteLine(json);
                          // 输出: {"Name":"Laptop","Ratings":[5,4,5]}
                          

                          技术细节

                          • 泛型反射:通过 MakeGenericType 动态创建泛型转换器。
                          • 递归序列化JsonSerializer.Deserialize<T>() 自动处理嵌套类型。

                          四、性能优化技巧

                          4.1 避免频繁创建对象

                          • 复用 JsonSerializerOptions:全局配置并复用,避免重复解析设置。
                          • 缓存 JsonConverter 实例:在工厂模式中缓存已创建的转换器。

                          4.2 使用高性能 API

                          • Utf8JsonReader / Utf8JsonWriter:比 JsonTextReader 快 30%+,且内存占用更低。
                          • Span 支持:避免不必要的字符串分配。

                          4.3 内存优化

                          • 异步处理:对于大型数据,使用 JsonSerializer.DeserializeAsync
                          • 流式处理:结合 Stream 逐块读写,避免一次性加载大文件。

                          五、高级场景:科学计数法转字符串

                          5.1 问题描述

                          数据库中的 decimal(18,2) 字段在 JSON 中可能被序列化为科学计数法:

                          { "Price": "1.23E+08" }
                          

                          而前端期望的是:

                          { "Price": 123000000 }
                          

                          5.2 解决方案

                          public class DecimalConverter : JsonConverter<decimal>
                          {
                              public override decimal Read(
                                  ref Utf8JsonReader reader, 
                                  Type typeToConvert, 
                                  JsonSerializerOptions options)
                              {
                                  // 解析 JSON 字符串为 decimal
                                  return decimal.Parse(reader.GetString()!);
                              }
                          
                              public override void Write(
                                  Utf8JsonWriter writer, 
                                  decimal value, 
                                  JsonSerializerOptions options)
                              {
                                  // 将 decimal 转为固定格式的字符串
                                  writer.WriteStringValue(value.ToString("F2"));
                              }
                          }
                          

                          绑定模型

                          public class Product
                          {
                              [JsonConverter(typeof(DecimalConverter))]
                              public decimal Price { get; set; }
                          }
                          

                          六、常见陷阱与解决方案

                          6.1 CanConvert 方法误判

                          • 问题:未正确覆盖 CanConvert,导致转换器无法匹配目标类型。
                          • 解决方案:在工厂模式中,严格判断类型是否符合预期。

                          6.2 嵌套类型处理失败

                          • 问题:转换器未处理嵌套对象(如 Dictionary<string, List<int>>)。
                          • 解决方案:递归调用 JsonSerializer,或手动拆解结构。

                          6.3 线程安全问题

                          • 问题:共享的 JsonSerializerOptions 被多个线程修改。
                          • 解决方案:使用 ThreadLocal<JsonSerializerOptions> 或每次创建新实例。

                          七、自定义转换器的设计哲学

                          模式适用类型核心方法典型场景
                          基本模式非泛型/封闭式泛型Read / Write日期格式化、枚举映射
                          工厂模式开放式泛型/多态CanConvert / CreateConverter泛型集合、动态类型

                          设计原则

                          1. 最小化依赖:避免在转换器中引入复杂逻辑。
                          2. 高内聚低耦合:每个转换器只处理一种类型或模式。
                          3. 性能优先:优先使用 Utf8JsonReaderUtf8JsonWriter
                          4. 可测试性:通过单元测试验证转换器的正确性。

                          代码模板

                          基本模式模板

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

                          工厂模式模板

                          public class CustomConverterFactory : JsonConverterFactory
                          {
                              public override bool CanConvert(Type typeToConvert)
                              {
                                  // 判断是否支持类型
                              }
                          
                              public override JsonConverter CreateConverter(
                                  Type typeToConvert, 
                                  JsonSerializerOptions options)
                              {
                                  // 动态创建转换器
                              }
                          }
                          

                          以上就是.NET中自定义JSON转换器的实战指南的详细内容,更多关于.NET自定义JSON转换器的资料请关注编程客栈(www.devze.com)其它相关文章!

                          0

                          上一篇:

                          下一篇:

                          精彩评论

                          暂无评论...
                          验证码 换一张
                          取 消

                          最新开发

                          开发排行榜