C#如何移除接口JSON响应中的marketingInfoDetails属性名实现扁平化输出
问题核心
你当前遇到的问题根源是CarInfo类将MarketingInfo/ServiceInfo/CarDetails作为嵌套属性定义,序列化时会自动将属性名作为外层key生成嵌套结构,你需要的扁平化效果本质是要将嵌套属性的字段提升到CarInfo的序列化层级,以下是不同适用场景的实现方案:
方案1:使用[JsonUnwrapped]特性(最简方案,适用于.NET 7+ 且使用System.Text.Json序列化)
.NET 7及以上版本的System.Text.Json原生提供了JsonUnwrapped特性,直接标记在需要扁平化的嵌套属性上即可,无需额外编码:
public class CarInfo { [JsonUnwrapped] [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public CarDetails Details { get; set; } [JsonUnwrapped] [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public ServiceInfo ServiceInfo { get; set; } [JsonUnwrapped] [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public MarketingInfo MarketingInfoDetails { get; set; } }
该特性会在序列化时自动把嵌套属性的内部字段展开到父对象层级,不会生成外层的属性名,且你不会同时赋值多个属性,不存在字段冲突问题。
方案2:自定义JsonConverter(兼容Newtonsoft.Json和低版本.NET)
如果你使用Newtonsoft.Json或者.NET版本低于7,可以通过自定义转换器实现扁平化序列化:
- 先实现转换器类:
public class CarInfoConverter : JsonConverter<CarInfo> { public override void WriteJson(JsonWriter writer, CarInfo value, JsonSerializer serializer) { writer.WriteStartObject(); // 序列化Details属性的内部字段 if (value.Details != null) { var jObj = JObject.FromObject(value.Details, serializer); foreach (var prop in jObj.Properties()) { prop.WriteTo(writer); } } // 序列化ServiceInfo属性的内部字段 if (value.ServiceInfo != null) { var jObj = JObject.FromObject(value.ServiceInfo, serializer); foreach (var prop in jObj.Properties()) { prop.WriteTo(writer); } } // 序列化MarketingInfoDetails属性的内部字段 if (value.MarketingInfoDetails != null) { var jObj = JObject.FromObject(value.MarketingInfoDetails, serializer); foreach (var prop in jObj.Properties()) { prop.WriteTo(writer); } } writer.WriteEndObject(); } public override CarInfo ReadJson(JsonReader reader, Type objectType, CarInfo existingValue, bool hasExistingValue, JsonSerializer serializer) { // 不需要反序列化可直接抛出异常 throw new NotImplementedException(); } }
- 给
CarInfo类标记转换器特性:
[JsonConverter(typeof(CarInfoConverter))] public class CarInfo { // 原有属性保持不变 }
方案3:多态重构(最优建模方案,适合长期维护的项目)
你的Cars数组元素结构随场景变化,本质是不同类型的对象,直接用多态建模可以从根源上消除多余的嵌套层:
- 定义抽象基类和对应场景的子类:
public abstract class CarBase { } // 营销场景的Car类 public class MarketingCar : CarBase { public string ContactPerson { get; set; } // 其他MarketingInfo的属性直接定义在这里 } // 服务场景的Car类 public class ServiceCar : CarBase { public string LastService { get; set; } // 其他ServiceInfo的属性 public int CarId { get; set; } public string LastOwner { get; set; } // 其他CarDetails的属性 }
- 修改
CarsModel的Cars属性类型:
public class CarsModel { public int OnStock { get; set; } public int Rented { get; set; } public List<CarBase> Cars { get; set; } }
赋值时直接根据场景添加对应类型的对象即可,序列化后自然就是你需要的平铺结构,无需额外序列化配置,模型结构清晰易维护。
方案4:JObject快速拼接(临时场景适用)
如果是短期快速迭代的小需求,不需要严格的强类型校验,可以直接用JObject构造响应:
var carsModel = new { OnStock = 11, Rented = 2, Cars = cars.Select(c => JObject.FromObject(new MarketingInfo { ContactPerson = "John Smith" // 其他属性赋值 })).ToList() };
内容的提问来源于stack exchange,提问作者user1765862
相关产品推荐
相关产品推荐

