导读:本期聚焦于小伙伴创作的《C#如何反序列化复杂JSON?System.Text.Json自定义Converter怎么实现》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何反序列化复杂JSON?System.Text.Json自定义Converter怎么实现》有用,将其分享出去将是对创作者最好的鼓励。

在C#项目中使用System.Text.Json处理JSON数据时,遇到字段格式特殊、类型映射复杂的情况,默认的序列化反序列化逻辑无法适配,这时候就需要通过自定义Converter来实现特殊处理逻辑。

C#如何反序列化复杂JSON?System.Text.Json自定义Converter怎么实现

System.Text.Json自定义Converter基础

System.Text.Json提供了JsonConverter基类,开发者可以通过继承该类并重写对应的方法,实现自定义的反序列化逻辑。核心需要重写的方法是Read,负责从JSON流中读取数据并转换为目标类型。

自定义Converter的基本结构如下:

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

public class CustomJsonConverter<T> : JsonConverter<T>
{
    // 重写Read方法,实现反序列化逻辑
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 自定义处理逻辑
        throw new NotImplementedException();
    }

    // 重写Write方法,实现序列化逻辑(如果需要序列化也需要自定义)
    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        // 自定义处理逻辑
        throw new NotImplementedException();
    }
}

场景一:处理特殊格式的日期字段

假设接口返回的JSON中日期字段是yyyyMMdd格式,而C#中对应的属性是DateTime类型,默认的反序列化会失败,这时候可以自定义日期Converter。

首先定义目标实体类:

public class OrderInfo
{
    public string OrderId { get; set; }
    // 日期字段是特殊格式,需要自定义Converter处理
    public DateTime CreateTime { get; set; }
}

然后实现日期格式的自定义Converter:

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

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)
    {
        // 读取JSON中的字符串值
        string dateStr = reader.GetString();
        // 按照指定格式解析日期
        if (DateTime.TryParseExact(dateStr, _format, null, System.Globalization.DateTimeStyles.None, out DateTime result))
        {
            return result;
        }
        throw new JsonException($"无法将字符串{dateStr}转换为DateTime格式");
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        // 序列化时按照指定格式输出
        writer.WriteStringValue(value.ToString(_format));
    }
}

使用的时候在实体属性上标注Converter即可:

public class OrderInfo
{
    public string OrderId { get; set; }

    [JsonConverter(typeof(CustomDateTimeConverter), "yyyyMMdd")]
    public DateTime CreateTime { get; set; }
}

测试反序列化代码:

using System;
using System.Text.Json;

class Program
{
    static void Main()
    {
        string json = "{"OrderId":"1001","CreateTime":"20240520"}";
        OrderInfo order = JsonSerializer.Deserialize<OrderInfo>(json);
        Console.WriteLine($"订单ID:{order.OrderId},创建时间:{order.CreateTime:yyyy-MM-dd}");
    }
}

场景二:处理枚举的自定义映射

如果JSON中枚举字段是字符串,而C#中枚举是数字,或者JSON中的字符串和枚举成员名称不一致,也需要自定义Converter。

比如定义枚举:

public enum OrderStatus
{
    Pending = 0,
    Paid = 1,
    Shipped = 2,
    Completed = 3
}

JSON中返回的订单状态是待支付已支付这样的中文,和枚举成员不匹配,自定义Converter实现映射:

using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;

public class OrderStatusConverter : JsonConverter<OrderStatus>
{
    private static readonly Dictionary<string, OrderStatus> _statusMap = new Dictionary<string, OrderStatus>
    {
        {"待支付", OrderStatus.Pending},
        {"已支付", OrderStatus.Paid},
        {"已发货", OrderStatus.Shipped},
        {"已完成", OrderStatus.Completed}
    };

    public override OrderStatus Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string statusStr = reader.GetString();
        if (_statusMap.TryGetValue(statusStr, out OrderStatus status))
        {
            return status;
        }
        throw new JsonException($"无法识别的订单状态:{statusStr}");
    }

    public override void Write(Utf8JsonWriter writer, OrderStatus value, JsonSerializerOptions options)
    {
        // 找到对应的中文描述输出
        foreach (var item in _statusMap)
        {
            if (item.Value == value)
            {
                writer.WriteStringValue(item.Key);
                return;
            }
        }
        writer.WriteNumberValue((int)value);
    }
}

实体类标注Converter:

public class OrderInfo
{
    public string OrderId { get; set; }

    [JsonConverter(typeof(CustomDateTimeConverter), "yyyyMMdd")]
    public DateTime CreateTime { get; set; }

    [JsonConverter(typeof(OrderStatusConverter))]
    public OrderStatus Status { get; set; }
}

场景三:处理嵌套复杂对象

如果JSON结构嵌套复杂,比如某个字段是动态结构,或者需要合并多个字段转换为一个对象,也可以通过自定义Converter实现。

假设JSON结构如下,需要把user_info下的nameage合并到UserInfo对象中:

{
    "order_id": "1001",
    "user_info": {
        "name": "张三",
        "age": 25
    },
    "total_price": 199.9
}

定义实体类:

public class OrderDetail
{
    public string OrderId { get; set; }
    public UserInfo UserInfo { get; set; }
    public decimal TotalPrice { get; set; }
}

public class UserInfo
{
    public string Name { get; set; }
    public int Age { get; set; }
}

实现自定义Converter处理嵌套结构:

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

public class OrderDetailConverter : JsonConverter<OrderDetail>
{
    public override OrderDetail Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 使用JsonDocument解析整个JSON对象
        using JsonDocument doc = JsonDocument.ParseValue(ref reader);
        JsonElement root = doc.RootElement;

        OrderDetail order = new OrderDetail();
        // 读取普通字段
        order.OrderId = root.GetProperty("order_id").GetString();
        order.TotalPrice = root.GetProperty("total_price").GetDecimal();

        // 处理嵌套的user_info字段
        JsonElement userInfoElement = root.GetProperty("user_info");
        order.UserInfo = new UserInfo
        {
            Name = userInfoElement.GetProperty("name").GetString(),
            Age = userInfoElement.GetProperty("age").GetInt32()
        };

        return order;
    }

    public override void Write(Utf8JsonWriter writer, OrderDetail value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("order_id", value.OrderId);
        writer.WriteStartObject("user_info");
        writer.WriteString("name", value.UserInfo.Name);
        writer.WriteNumber("age", value.UserInfo.Age);
        writer.WriteEndObject();
        writer.WriteNumber("total_price", value.TotalPrice);
        writer.WriteEndObject();
    }
}

在实体类上标注Converter即可正常使用:

[JsonConverter(typeof(OrderDetailConverter))]
public class OrderDetail
{
    public string OrderId { get; set; }
    public UserInfo UserInfo { get; set; }
    public decimal TotalPrice { get; set; }
}

全局注册Converter

如果不想在每一个实体属性上单独标注Converter,也可以在JsonSerializerOptions中全局注册,所有符合类型的属性都会使用该Converter:

using System.Text.Json;

class Program
{
    static void Main()
    {
        JsonSerializerOptions options = new JsonSerializerOptions();
        // 全局注册日期Converter
        options.Converters.Add(new CustomDateTimeConverter("yyyyMMdd"));
        // 全局注册枚举Converter
        options.Converters.Add(new OrderStatusConverter());

        string json = "{"OrderId":"1001","CreateTime":"20240520","Status":"已支付"}";
        OrderInfo order = JsonSerializer.Deserialize<OrderInfo>(json, options);
        Console.WriteLine($"订单状态:{order.Status}");
    }
}

注意事项

  • 自定义Converter的Read方法需要正确处理Utf8JsonReader的读取位置,避免读取错位导致解析失败。
  • 如果Converter需要处理可空类型,建议继承JsonConverter<T?>或者在逻辑中处理null值的情况。
  • 全局注册的Converter会覆盖默认的逻辑,如果有特殊属性需要不同的处理,可以在属性上单独标注Converter,属性标注的优先级高于全局注册。

C#System.Text.Json自定义ConverterJSON反序列化修改时间:2026-07-04 22:54:43

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。