同一航空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
相关产品推荐
相关产品推荐

