You need to enable JavaScript to run this app. C#中如何配置DTO类以兼容两种结构集合的JSON序列化与反序列化
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何配置DTO类以兼容两种结构集合的JSON序列化与反序列化

适配两种JSON结构的DTO实现方案

核心需求

基于Newtonsoft.Json构建单个Message DTO,同时满足三个要求:

  • 反序列化兼容接口返回的两种Attachments结构(直接数组 / 嵌套"Attachment"节点的对象)
  • 序列化输出完全符合入参要求的嵌套对象结构
  • 无需额外维护两套请求/响应模型

结构差异说明

入参要求的JSON结构

{
  "MessageText": "text",
  "Attachments": {
    "Attachment": [
      { "FileName": "file1" },
      { "FileName": "file2" }
    ]
  }
}

接口返回的兼容JSON结构

  1. 直接数组结构:
{
  "MessageText": "text",
  "Attachments": [
    { "FileName": "file1" },
    { "FileName": "file2" }
  ]
}
  1. 嵌套节点结构(和入参结构一致,同样需要兼容解析):
{
  "MessageText": "text",
  "Attachments": {
    "Attachment": [
      { "FileName": "file1" },
      { "FileName": "file2" }
    ]
  }
}

现有实现的问题

当前实现的Attachments类直接继承List<Attachment>,会导致:

  • 序列化时直接输出数组结构,不符合入参的嵌套对象要求
  • 反序列化时遇到嵌套对象结构(带Attachment节点),无法正确解析为列表

最终实现代码

1. 自定义JSON转换器

通过重写JsonConverter的读写逻辑,同时处理序列化输出和反序列化的结构兼容:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class AttachmentsJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Attachments).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var attachments = new Attachments();
        // 兼容两种返回结构
        switch (reader.TokenType)
        {
            case JsonToken.StartArray:
                // 直接数组结构:直接反序列化
                var arrayItems = serializer.Deserialize<List<Attachment>>(reader);
                attachments.AddRange(arrayItems);
                break;
            case JsonToken.StartObject:
                // 嵌套节点结构:提取"Attachment"字段后反序列化
                var jObject = JObject.Load(reader);
                var nestedItems = jObject["Attachment"]?.ToObject<List<Attachment>>();
                if (nestedItems != null)
                {
                    attachments.AddRange(nestedItems);
                }
                break;
        }
        return attachments;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var attachments = (Attachments)value;
        // 统一输出入参要求的嵌套结构
        writer.WriteStartObject();
        writer.WritePropertyName("Attachment");
        serializer.Serialize(writer, attachments.ToList());
        writer.WriteEndObject();
    }
}

2. 修正后的DTO定义

给Attachments类绑定自定义转换器特性,无需修改其他业务属性:

public class Message
{
    public string MessageText { get; set; }
    public Attachments Attachments { get; set; } = new Attachments();
}

public class Attachment
{
    public string FileName { get; set; }
}

[JsonConverter(typeof(AttachmentsJsonConverter))]
public class Attachments : List<Attachment> { }

测试匹配说明

上述实现可以完全满足给定的3个单元测试用例:

  • TestMethodDeSerialization1:反序列化直接数组结构时,转换器识别StartArray令牌,直接解析为列表
  • TestMethodDeSerialization2:反序列化嵌套对象结构时,转换器识别StartObject令牌,自动提取Attachment节点内容解析
  • TestMethodSerialization:序列化时统一包装为带Attachment属性的对象,输出完全匹配入参Schema要求

内容的提问来源于stack exchange,提问作者Sybaris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.14 05:06:03