如何全局配置JSON从蛇形命名到驼峰命名的反序列化
全局配置蛇形命名与驼峰命名的JSON序列化/反序列化规则
问题场景
需要反序列化如下蛇形命名的JSON响应:
{ "result": [ "......" ], "plugins_versions": { "age": "agegender.AgeDetector", "gender": "agegender.GenderDetector", "detector": "facenet.FaceDetector", "calculator": "facenet.Calculator" } }
测试代码模拟反序列化过程(使用System.Text.Json):
using System.Text.Json; using System.Text.Json.Serialization; var jsonOptions = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }; var jsonString = "{\"plugins_versions\": {\"age\": \"agegender.AgeDetector\"}}"; Console.WriteLine(jsonString); var parsedText = JsonSerializer.Deserialize<Response>(jsonString, options: jsonOptions); Console.WriteLine(parsedText.PluginsVersions.Age); class Response { public PluginVersion PluginsVersions { get; set; } } class PluginVersion { public string Age { get; set; } }
设置PropertyNamingPolicy = JsonNamingPolicy.CamelCase后无法反序列化plugins_versions字段,仅手动添加[JsonPropertyName("plugins_versions")]特性才能成功。需要全局配置蛇形命名与Pascal命名(类属性的大驼峰)的转换规则,避免逐个字段添加特性。
问题原因
默认的JsonNamingPolicy.CamelCase仅支持Pascal命名与小驼峰命名的双向转换,无法识别蛇形命名(下划线分隔)的JSON字段。
你之前自定义的SnakeCaseToCamelCaseNamingPolicy逻辑方向错误:JsonNamingPolicy.ConvertName方法的作用是将.NET类的属性名转换为JSON字段名(序列化时),反序列化时则通过类属性名转换后的结果匹配JSON字段。而你的代码是把蛇形命名转成Pascal命名,与实际需求方向相反,因此不生效。
解决方案
编写正确的自定义命名策略,实现Pascal命名到蛇形命名的转换,这样序列化和反序列化时都能自动匹配:
1. 自定义命名策略类
using System.Text.Json; namespace Test; public class PascalToSnakeCaseNamingPolicy : JsonNamingPolicy { public override string ConvertName(string name) { if (string.IsNullOrEmpty(name)) return name; var result = new System.Text.StringBuilder(); // 首字母转小写 result.Append(char.ToLowerInvariant(name[0])); for (int i = 1; i < name.Length; i++) { // 遇到大写字母,先加下划线再转小写 if (char.IsUpper(name[i])) { result.Append('_'); result.Append(char.ToLowerInvariant(name[i])); } else { result.Append(name[i]); } } return result.ToString(); } }
2. 全局应用该策略
修改JsonSerializerOptions,使用自定义的命名策略:
using System.Text.Json; var jsonOptions = new JsonSerializerOptions() { PropertyNamingPolicy = new PascalToSnakeCaseNamingPolicy(), // 可添加其他配置,比如忽略null值 // DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; // 反序列化测试 var jsonString = "{\"plugins_versions\": {\"age\": \"agegender.AgeDetector\"}}"; var parsedText = JsonSerializer.Deserialize<Response>(jsonString, jsonOptions); Console.WriteLine(parsedText.PluginsVersions.Age); // 输出:agegender.AgeDetector // 序列化测试(自动转成蛇形命名JSON) var response = new Response { PluginsVersions = new PluginVersion { Age = "test_version" } }; var serializedJson = JsonSerializer.Serialize(response, jsonOptions); Console.WriteLine(serializedJson); // 输出:{"plugins_versions":{"age":"test_version"}} class Response { public PluginVersion PluginsVersions { get; set; } } class PluginVersion { public string Age { get; set; } }
逻辑说明
- 该策略会将.NET类的Pascal命名属性(如
PluginsVersions)转换为蛇形命名的JSON字段(plugins_versions)。 - 反序列化时,.NET会自动将类属性名转换为蛇形命名,与JSON中的字段匹配,无需手动添加特性。
- 序列化时,也会自动将类属性转成蛇形命名的JSON,实现双向统一的全局配置。
内容的提问来源于stack exchange,提问作者Asadbek Sindarov
相关产品推荐
相关产品推荐

