You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一航空API返回不同结构响应,如何适配实现正常反序列化?

解决方案

实现思路

这是API返回字段动态切换「单个对象/数组」的典型兼容性问题,核心解法为:

  • 统一将实体类中对应字段定义为List<T>类型,兼容1个或多个元素的场景
  • 自定义JSON转换器,反序列化时自动判断节点类型:如果是对象就包装成长度为1的列表,如果是数组就直接反序列化为列表

步骤1:调整实体类结构

将两个动态结构的字段都改为列表类型,后续业务层统一按列表处理即可:

public class OriginDestinationOption
{
    // 改为List<FlightSegment>,兼容单个对象和数组场景
    public List<FlightSegment> FlightSegment { get; set; }
    public string RPH { get; set; }
}

public class OriginDestinationOptions
{
    // 改为List<OriginDestinationOption>,兼容单个对象和数组场景
    public List<OriginDestinationOption> OriginDestinationOption { get; set; }
}

public class AirItinerary
{
    public OriginDestinationOptions OriginDestinationOptions { get; set; }
}

// 补充依赖的基础类定义,可按需补充缺失字段
public class FlightSegment
{
    public string Status { get; set; }
    public Airport DepartureAirport { get; set; }
    public string Comment { get; set; }
    public string ConnectionType { get; set; }
    public string FareBasisCode { get; set; }
    public Airport ArrivalAirport { get; set; }
    public BookingClass BookingClassAvails { get; set; }
    public string DepartureDay { get; set; }
    public string NumberInParty { get; set; }
    public string ResBookDesigCode { get; set; }
    public bool E_TicketEligibility { get; set; }
    public string RPH { get; set; }
    public DateTime DepartureDateTime { get; set; }
    public DateTime ArrivalDateTime { get; set; }
    public bool ValidConnectionInd { get; set; }
    public string FlightNumber { get; set; }
    public Airline OperatingAirline { get; set; }
}

public class Airport
{
    public string CodeContext { get; set; }
    public string LocationCode { get; set; }
}

public class BookingClass
{
    public string CabinType { get; set; }
    public string BookingClassAvail { get; set; }
}

public class Airline
{
    public string CompanyShortName { get; set; }
    public string Description { get; set; }
    public string Code { get; set; }
}

步骤2:实现通用单对象/数组兼容转换器

根据你使用的序列化库选择对应实现:

方案A:使用Newtonsoft.Json(Json.NET)

首先实现通用转换器:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

public class SingleOrArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<T>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }
        return new List<T> { token.ToObject<T>() };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 序列化逻辑可按需调整:比如列表长度为1时输出对象,否则输出数组
        serializer.Serialize(writer, value);
    }
}

然后给实体类的对应字段加上转换器特性:

public class OriginDestinationOption
{
    [JsonConverter(typeof(SingleOrArrayConverter<FlightSegment>))]
    public List<FlightSegment> FlightSegment { get; set; }
    public string RPH { get; set; }
}

public class OriginDestinationOptions
{
    [JsonConverter(typeof(SingleOrArrayConverter<OriginDestinationOption>))]
    public List<OriginDestinationOption> OriginDestinationOption { get; set; }
}

方案B:使用System.Text.Json(.NET Core 3.0+ / .NET 5+ 自带)

实现通用转换器:

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

public class SingleOrArrayConverter<T> : JsonConverter<List<T>>
{
    public override List<T>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        if (doc.RootElement.ValueKind == JsonValueKind.Array)
        {
            return doc.RootElement.Deserialize<List<T>>(options);
        }
        return new List<T> { doc.RootElement.Deserialize<T>(options) };
    }

    public override void Write(Utf8JsonWriter writer, List<T> value, JsonSerializerOptions options)
    {
        // 序列化逻辑按需调整
        JsonSerializer.Serialize(writer, value, options);
    }
}

然后给对应字段加上特性:

public class OriginDestinationOption
{
    [JsonConverter(typeof(SingleOrArrayConverter<FlightSegment>))]
    public List<FlightSegment> FlightSegment { get; set; }
    public string RPH { get; set; }
}

public class OriginDestinationOptions
{
    [JsonConverter(typeof(SingleOrArrayConverter<OriginDestinationOption>))]
    public List<OriginDestinationOption> OriginDestinationOption { get; set; }
}

步骤3:反序列化调用示例

以Newtonsoft.Json为例,无需额外判断,直接正常反序列化即可:

// 不管是单程还是往返的响应JSON,都可以直接反序列化
var airItinerary = JsonConvert.DeserializeObject<AirItinerary>(jsonResponse);

// 业务层统一按列表处理即可
foreach (var option in airItinerary.OriginDestinationOptions.OriginDestinationOption)
{
    foreach (var segment in option.FlightSegment)
    {
        // 处理航段信息
        Console.WriteLine($"航班号:{segment.FlightNumber},出发时间:{segment.DepartureDateTime}");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:24:05