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

如何使用System.Text.Json按类定制属性与字典键的序列化规则

核心问题说明

  1. System.Text.Json默认序列化继承Dictionary<,>的类型时,仅输出字典内的键值对,不会序列化类自身定义的公共属性
  2. 全局PropertyNamingPolicy无法针对不同类型实现差异化的键命名规则

实现方案

通过为Product和Store分别定义专属的JsonConverter,同时处理自有属性序列化、差异化键命名两个需求。

步骤1:定义两个自定义转换器

using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

public class ProductJsonConverter : JsonConverter<Product>
{
    // 不需要反序列化逻辑直接抛出异常
    public override Product Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Product value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // 序列化类自有属性,过滤Dictionary自带的Keys/Values/Count等属性
        var selfProperties = typeof(Product).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => !typeof(Dictionary<string, object>).GetProperties().Select(dp => dp.Name).Contains(p.Name)
                        && p.GetMethod != null);
        foreach (var prop in selfProperties)
        {
            var propValue = prop.GetValue(value);
            if (propValue == null) continue;
            // 自有属性名转全小写
            writer.WritePropertyName(prop.Name.ToLowerInvariant());
            JsonSerializer.Serialize(writer, propValue, prop.PropertyType, options);
        }

        // 序列化字典内的键值对,键转全小写
        foreach (var kvp in value)
        {
            writer.WritePropertyName(kvp.Key.ToLowerInvariant());
            JsonSerializer.Serialize(writer, kvp.Value, options);
        }

        writer.WriteEndObject();
    }
}

public class StoreJsonConverter : JsonConverter<Store>
{
    // 字典键需要拼接的前缀,可按需修改
    private const string KeyPrefix = "prefix_";

    public override Store Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Store value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // 序列化类自有属性
        var selfProperties = typeof(Store).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => !typeof(Dictionary<string, object>).GetProperties().Select(dp => dp.Name).Contains(p.Name)
                        && p.GetMethod != null);
        foreach (var prop in selfProperties)
        {
            var propValue = prop.GetValue(value);
            if (propValue == null) continue;
            writer.WritePropertyName(prop.Name.ToLowerInvariant());
            JsonSerializer.Serialize(writer, propValue, prop.PropertyType, options);
        }

        // 序列化字典内的键值对,键转全小写后拼接前缀
        foreach (var kvp in value)
        {
            writer.WritePropertyName($"{KeyPrefix}{kvp.Key.ToLowerInvariant()}");
            JsonSerializer.Serialize(writer, kvp.Value, options);
        }

        writer.WriteEndObject();
    }
}

步骤2:给对应类绑定转换器

直接在类定义上添加JsonConverter特性,序列化时会自动触发对应转换器逻辑:

[JsonConverter(typeof(ProductJsonConverter))]
public class Product : Dictionary<string, object> {
    public string ProductId { get; set; }
    public IList<Store> Stores { get; set; }
}

[JsonConverter(typeof(StoreJsonConverter))]
public class Store : Dictionary<string, object> {
    public string StoreId { get; set; }
}

步骤3:直接执行序列化

不需要额外配置全局命名策略,直接正常序列化即可得到符合要求的输出:

IEnumerable<Product> products = GetProducts(); 
var serializeOptions = new JsonSerializerOptions
{
    WriteIndented = true // 可选,格式化输出JSON
};
string resultJson = JsonSerializer.Serialize(products, serializeOptions);

注意事项

  • 转换器中已经过滤了Dictionary自带的Keys、Values、Count等内置属性,不会输出冗余内容
  • 若后续给Product或Store新增自有属性,不需要修改转换器代码,会自动兼容处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 20:27:03