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

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,可以通过自定义转换器实现扁平化序列化:

  1. 先实现转换器类:
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();
    }
}
  1. 给CarInfo类标记转换器特性:
[JsonConverter(typeof(CarInfoConverter))]
public class CarInfo
{
    // 原有属性保持不变
}

方案3:多态重构(最优建模方案,适合长期维护的项目)

你的Cars数组元素结构随场景变化,本质是不同类型的对象,直接用多态建模可以从根源上消除多余的嵌套层:

  1. 定义抽象基类和对应场景的子类:
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的属性
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 13:09:03