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

如何用[JsonExtensionData]与JsonNamingPolicy.CamelCase正确序列化Dictionary?

System.Text.Json中[JsonExtensionData]字典键未应用驼峰命名的问题

我需要使用JsonNamingPolicy.CamelCase序列化对象,但在将Dictionary与[JsonExtensionData]属性配合使用时,扩展数据的键未被转为驼峰格式,不符合预期。

示例代码

public class Test
{
    public Dictionary<string, object> Labels { get; set; } = new();

    [JsonExtensionData]
    public Dictionary<string, object> MetaInfo { get; set; } = new();

    public Dictionary<string, object>? Nullable { get; set; } = null;
}

public class TestContent
{
    public string? Value { get; set; }
}

System.Text.Json 配置

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
};

var test = new Test
{
    Labels = new Dictionary<string, object>
    {
        { "Test1", new TestContent{ Value = "TestContent1" } }, 
        { "Test2", new TestContent { Value = null } },
    },
    MetaInfo = new Dictionary<string, object>
    {
        { "Test1", new TestContent{ Value = "TestContent1" } },
        { "Test2", new TestContent { Value = null } },
    }
};

var result = JsonSerializer.Serialize(test, options);
System.Console.WriteLine(result);

预期输出

扩展数据的键应转为驼峰格式(test1、test2):

{
    "labels":{
        "test1":{
            "value": "TestContent1"
        },
        "test2":{
        }
    },
    "test1":{
        "value": "TestContent1"
    },
    "test2":{
    }
}

实际输出

扩展数据的键仍为原格式(Test1、Test2):

{
    "labels":{
        "test1":{
            "value": "TestContent1"
        },
        "test2":{
            
        }
    },
    "Test1":{
        "value": "TestContent1"
    },
    "Test2":{
        
    }
}

可见JsonNamingPolicy.CamelCase对labels生效,但对扩展数据的键不生效。切换为Newtonsoft.Json时可正常生成驼峰格式的键:

var contractResolver = new DefaultContractResolver
{
    NamingStrategy = new CamelCaseNamingStrategy
    {
        ProcessDictionaryKeys = true,
        ProcessExtensionDataNames = true,
        OverrideSpecifiedNames = false,
    }
};

var settings = new JsonSerializerSettings
{
    ContractResolver = contractResolver,
    NullValueHandling = NullValueHandling.Ignore,
};

var result = JsonConvert.SerializeObject(test, settings);       
System.Console.WriteLine(result);
// {"labels":{"test1":{"value":"TestContent1"},"test2":{}},"test1":{"value":"TestContent1"},"test2":{}}

请问我是否遗漏了某些设置?


解决方案

这是System.Text.Json与Newtonsoft.Json的默认行为差异:System.Text.Json默认不会对标记了[JsonExtensionData]的字典键应用命名策略,即使配置了DictionaryKeyPolicy也不会生效。

1. .NET 7及以上版本

直接在JsonSerializerOptions中新增ExtensionDataNamingPolicy配置即可,这是.NET 7新增的专门针对扩展数据的命名策略选项:

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
    ExtensionDataNamingPolicy = JsonNamingPolicy.CamelCase // 新增此配置
};

2. .NET 6及以下版本

需要自定义JsonConverter来处理扩展数据的键转换:

首先创建转换器:

public class CamelCaseExtensionDataConverter : JsonConverter<Dictionary<string, object>>
{
    private readonly JsonNamingPolicy _camelCasePolicy = JsonNamingPolicy.CamelCase;

    public override Dictionary<string, object>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 反序列化时可根据需求将驼峰键转回原格式,此处按默认逻辑处理
        var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);
        return dict?.ToDictionary(kv => _camelCasePolicy.ConvertName(kv.Key), kv => kv.Value);
    }

    public override void Write(Utf8JsonWriter writer, Dictionary<string, object> value, JsonSerializerOptions options)
    {
        foreach (var kvp in value)
        {
            var camelCaseKey = _camelCasePolicy.ConvertName(kvp.Key);
            writer.WritePropertyName(camelCaseKey);
            JsonSerializer.Serialize(writer, kvp.Value, options);
        }
    }
}

然后在MetaInfo属性上标记转换器:

[JsonExtensionData]
[JsonConverter(typeof(CamelCaseExtensionDataConverter))]
public Dictionary<string, object> MetaInfo { get; set; } = new();

或者在JsonSerializerOptions中全局注册转换器(适用于多个类有扩展数据需要处理的场景):

options.Converters.Add(new CamelCaseExtensionDataConverter());

完成以上配置后,扩展数据的键即可转为驼峰格式,与预期输出一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 05:35:29