C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > .NET自定义JSON转换器

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

作者:墨夶

在.NET开发中,JSON序列化与反序列化是日常开发的核心操作,然而,标准的序列化器(如System.Text.Json)并不能满足所有场景需求,自定义JSON转换器正是解决这些问题的利器,本文将通过基本模式和工厂模式的实战案例,带你掌握自定义转换器的核心技巧,需要的朋友可以参考下

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

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

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

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

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

2.1 适用场景

2.2 核心方法

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

场景需求

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, 
        Type 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"}

技术细节

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

3.1 适用场景

3.2 核心方法

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

场景需求

代码实现

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<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]}

技术细节

四、性能优化技巧

4.1 避免频繁创建对象

4.2 使用高性能 API

4.3 内存优化

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

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 方法误判

6.2 嵌套类型处理失败

6.3 线程安全问题

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

模式适用类型核心方法典型场景
基本模式非泛型/封闭式泛型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转换器的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文