You need to enable JavaScript to run this app. Newtonsoft.Json序列化时如何将CustomConfigObject属性内容平铺到父层级
优惠活动
大模型
产品
解决方案
定价
更多

Newtonsoft.Json序列化时如何将CustomConfigObject属性内容平铺到父层级

针对Config模型的平铺序列化最优实现

你需要的效果完全可以通过自定义Newtonsoft.Json转换器实现,不需要为CustomConfigObject下的所有子属性写冗余的getter方法,可维护性远高于临时方案。

方案核心逻辑

完全接管Config类型的序列化过程:

  • 手动输出Config类中定义的常规业务属性(比如id、name这类)
  • 直接读取CustomConfigObject里的所有节点字段,平铺到当前JSON层级
  • 自动跳过原始存储的CustomConfig字符串、CustomConfigObject嵌套键的输出,不会产生多余字段

具体实现

1. 编写专属序列化转换器

public class ConfigFlattenJsonConverter : JsonConverter
{
    // 仅需要自定义序列化逻辑,反序列化因为是从数据库读取实体,不需要处理
    public override bool CanWrite => true;
    public override bool CanRead => false;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var config = (Config)value;
        writer.WriteStartObject();

        // 遍历Config类本身的公开属性,跳过不需要输出的两个存储字段
        var normalProperties = typeof(Config)
            .GetProperties()
            .Where(prop => 
                prop.Name != nameof(Config.CustomConfig) && 
                prop.Name != nameof(Config.CustomConfigObject));

        foreach (var prop in normalProperties)
        {
            var propValue = prop.GetValue(config);
            writer.WritePropertyName(prop.Name);
            serializer.Serialize(writer, propValue, prop.PropertyType);
        }

        // 直接将CustomConfigObject的所有字段平铺到当前层级
        if (config.CustomConfigObject != null)
        {
            foreach (var childNode in config.CustomConfigObject.Properties())
            {
                writer.WritePropertyName(childNode.Name);
                childNode.Value.WriteTo(writer);
            }
        }

        writer.WriteEndObject();
    }

    // 关闭自定义反序列化逻辑,不需要实现
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        // 仅对Config类型生效
        return objectType == typeof(Config);
    }
}

2. 转换器的使用方式

两种选择都可以,根据你的项目习惯选:

  • 序列化时临时指定转换器,不需要修改Config类定义:
    var serializeSettings = new JsonSerializerSettings
    {
        Converters = new List<JsonConverter> { new ConfigFlattenJsonConverter() }
    };
    // 直接序列化整个Config数组即可得到平铺后的JSON
    string finalOutput = JsonConvert.SerializeObject(configList, Formatting.Indented, serializeSettings);
    
  • 给Config类加特性绑定转换器,全局生效:
    [JsonConverter(typeof(ConfigFlattenJsonConverter))]
    public class Config
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string CustomConfig { get; set; }
        public JObject CustomConfigObject { get; set; }
    }
    

方案优势

  • 不需要预先枚举CustomConfigObject下的所有可能字段,哪怕后续不同配置行的JSON结构有差异,也会被自动平铺,完全不用改动代码
  • 不会因为嵌套键产生多余层级,输出结构完全匹配你要的无customConfigObject嵌套的目标JSON
  • 可以灵活处理字段冲突:如果后续遇到Config本身属性和CustomConfigObject内字段重名的场景,只需要在转换器逻辑里加几行判断,指定优先保留哪一侧的值即可
  • 自动过滤掉数据库存储用的两个原始字段,不会把冗余的内部存储内容暴露到最终输出的客户端配置blob里

内容的提问来源于stack exchange,提问作者Rob Jeffrey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 15:15:03