System.Text.Json 自定义序列化 实现动态键名的扁平JSON输出
动态键扁平化JSON输出实现方案
针对需要将CampaignId属性值直接作为JSON动态键、输出无嵌套结构的需求,可通过以下两种不依赖修改现有类业务逻辑的方案实现:
方案1:直接转换为字典序列化(最简实现)
无需改动原有类结构,在序列化前将原模型转换为键值对完全匹配目标结构的字典,直接序列化字典即可得到要求的输出。
调整原有Main方法中的序列化逻辑:
// 遍历原模型构造扁平化字典 var resultDict = new Dictionary<string, List<int>>(); foreach (var mapItem in campaignAccountMap.Campaigns) { resultDict[mapItem.CampaignId] = mapItem.AccountIds; } // 序列化并输出目标JSON string jsonString = JsonSerializer.Serialize(resultDict, new JsonSerializerOptions { WriteIndented = true }); Console.Write(jsonString);
- 优势:逻辑直观无隐式行为,没有额外的框架学习成本,适配快速开发场景。
- 注意:若存在重复的
CampaignId,字典会自动覆盖同键下的旧值,可根据业务需求补充重复校验逻辑。
方案2:自定义System.Text.Json转换器(零业务侵入)
如果希望完全保留原有序列化调用逻辑(即不修改JsonSerializer.Serialize<CampaignAccountMap>(campaignAccountMap)的调用方式),可通过自定义JsonConverter实现序列化规则适配,不需要手动做中间字典转换。
首先编写针对CampaignAccountMap的序列化转换器:
public class CampaignAccountMapCustomConverter : JsonConverter<CampaignAccountMap> { // 反序列化逻辑可根据业务需求补充,以下仅实现序列化输出 public override CampaignAccountMap Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException("反序列化逻辑可按需扩展"); } public override void Write(Utf8JsonWriter writer, CampaignAccountMap value, JsonSerializerOptions options) { writer.WriteStartObject(); foreach (var item in value.Campaigns) { // 动态取CampaignId值作为JSON对象的键 writer.WritePropertyName(item.CampaignId); // 序列化对应的AccountIds列表作为键值 JsonSerializer.Serialize(writer, item.AccountIds, options); } writer.WriteEndObject(); } }
转换器使用方式有两种:
- 序列化时将转换器注入选项,无需修改原有类定义:
var serializeOptions = new JsonSerializerOptions { Converters = { new CampaignAccountMapCustomConverter() }, WriteIndented = true }; // 原有模型实例构造逻辑完全不变 string jsonString = JsonSerializer.Serialize(campaignAccountMap, serializeOptions); Console.Write(jsonString);
- 给
CampaignAccountMap类添加特性,后续所有对该类型的序列化自动应用规则:
[JsonConverter(typeof(CampaignAccountMapCustomConverter))] class CampaignAccountMap { // 原有类的属性、构造函数逻辑完全保留,无任何改动 public List<CampaignAccountMapItem> Campaigns { get; set; } public CampaignAccountMap() { Campaigns = new List<CampaignAccountMapItem>(); } }
- 优势:业务层序列化代码和原有写法完全一致,没有冗余的中间转换步骤,动态键直接从对象实例的属性值生成,完全匹配需求。
两个方案均基于.NET内置的System.Text.Json实现,不需要引入第三方序列化库,也不需要通过静态特性做固定字段名的映射,完全满足动态键生成的要求。
内容的提问来源于stack exchange,提问作者Wesley Smith
相关产品推荐
相关产品推荐

