practical-aspnetcore:使用 System.Text.Json 自定义 SnakeCaseNamingPolicy 实现 snake_case JSON 命名(json-7 实战)
示例工程【免费下载链接】practical-aspnetcorePractical samples of ASP.NET Core 11, 10, 9, 8.0, 7.0, 6.0, 5.0, 3.1, 2.2, and 2.1,projects you can use. Readme contains explanations on all projects.项目地址https://gitcode.com/gh_mirrors/pr/practical-aspnetcore点击查看免费下载本篇基于 practical-aspnetcore 仓库中的 json-7 示例讲解如何为System.Text.Json实现一个自定义命名策略JsonNamingPolicy让序列化输出的 JSON 属性名与字典键全部转为 snake_case 形式。读完本篇你将掌握完整的SnakeCaseNamingPolicy实现代码、底层状态机的逐状态解析以及仓库中 json-8 对两种 snake_case 转换实现的 Benchmark 对比方式。示例目标与运行环境json-7 的原始说明只有一句话概括Create a custom naming policy that generate JSON property names in snake_case.Code for converting CamelCase property to snake_case is obtained from Newtonsoft.Json.即编写一个自定义命名策略类使System.Text.Json生成的 JSON 属性名遵循 snake_case 规则其中 CamelCase 转 snake_case 的核心算法取自 Newtonsoft.Json 的StringUtils.ToSnakeCase实现见 json-7 主程序 中的出处注释。运行环境方面从 json-7.csproj 看目标框架为net10.0LangVersion设为preview仓库根目录 global.json 锁定 SDK 版本10.0.0rollForward: major、allowPrerelease: true因此在 .NET 10 SDK或允许前向滚动的主版本 SDK环境下dotnet run即可运行。完整示例代码json-7 的 Program.cs 是一个标准的 Minimal API 单文件应用结构分为三部分一个 GET 端点演示序列化效果、一个StringUtils静态类提供 snake_case 转换算法、一个SnakeCaseNamingPolicy策略类。1. 用 JsonSerializerOptions 挂载命名策略端点部分使用匿名类型构造 payload并传入JsonSerializerOptionsProgram.cs#L6-L33var app WebApplication.Create(); app.MapGet(/, () { var payload new { Name Annie, Age 33, IsMarried false, CurrentTime DateTimeOffset.UtcNow, Characters new { Funny true, Feisty true, Brilliant true, FOMA false, HighEmpathy true } }; var options new JsonSerializerOptions { WriteIndented true, DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy new SnakeCaseNamingPolicy(), DictionaryKeyPolicy new SnakeCaseNamingPolicy() }; return Results.Json(payload, options); }); app.Run();这里有两个策略挂载点与 json-2 示例的说明一致PropertyNamingPolicy作用于对象属性名。若不设置属性会按 C# 的 PascalCase 原样输出内置策略里最常用的替代是JsonNamingPolicy.CamelCase而 snake_case 没有内置策略所以需要自己实现DictionaryKeyPolicy作用于字典键。本示例中Characters虽是匿名类型但仓库的姊妹示例 json-2 的 Program.cs 里Characters是Dictionarystring, bool其键Funny、FOMA等同样需要策略转换因此两项都设置为new SnakeCaseNamingPolicy()。payload 特意选用了多种形态的属性名Name、IsMarried、连续大写的FOMA、复合词HighEmpathy恰好覆盖了 snake_case 转换的几类边界情况方便直接观察输出。2. 策略类一行委托给转换算法public class SnakeCaseNamingPolicy : JsonNamingPolicy { public override string ConvertName(string name) { return StringUtils.ToSnakeCase(name); } }JsonNamingPolicy是抽象基类只需重写ConvertName(string name)返回转换后的属性名。这里把真正的转换逻辑委托给下面的StringUtils。3. snake_case 转换算法来自 Newtonsoft.Json 的状态机转换算法直接移植自 Newtonsoft.Json 的StringUtils.ToSnakeCaseProgram.cs#L38-L119文件内注释注明了原始出处为 Newtonsoft.Json 仓库的StringUtils.cs并标注 Modified to use span。核心是一个四状态状态机internal static class StringUtils { internal enum SnakeCaseState { Start, Lower, Upper, NewWord } public static string ToSnakeCase(string s) { if (string.IsNullOrEmpty(s)) { return s; } StringBuilder sb new StringBuilder(); SnakeCaseState state SnakeCaseState.Start; for (int i 0; i s.Length; i) { if (s[i] ) { if (state ! SnakeCaseState.Start) { state SnakeCaseState.NewWord; } } else if (char.IsUpper(s[i])) { switch (state) { case SnakeCaseState.Upper: bool hasNext (i 1 s.Length); if (i 0 hasNext) { char nextChar s[i 1]; if (!char.IsUpper(nextChar) nextChar ! _) { sb.Append(_); } } break; case SnakeCaseState.Lower: case SnakeCaseState.NewWord: sb.Append(_); break; } char c; #if HAVE_CHAR_TO_LOWER_WITH_CULTURE c char.ToLower(s[i], CultureInfo.InvariantCulture); #else c char.ToLowerInvariant(s[i]); #endif sb.Append(c); state SnakeCaseState.Upper; } else if (s[i] _) { sb.Append(_); state SnakeCaseState.Start; } else { if (state SnakeCaseState.NewWord) { sb.Append(_); } sb.Append(s[i]); state SnakeCaseState.Lower; } } return sb.ToString(); } }四个状态的含义状态含义Start起始状态或者刚处理完一个下划线后的状态Lower刚输出过一个小写字符即处于普通单词内部Upper刚输出过一个刚被转成小写的字母即处于连续大写的尾部NewWord刚遇到一个空格下一个字符前需要补一个下划线逐分支解读遇到空格s[i] 若不在Start态则切换到NewWord等下一个字符落笔前补上_。这保证New Word这类带空格的名称能转换为new_word。遇到大写字母char.IsUpper(s[i])这是状态机的核心分两种情形当前处于Upper态前一个字符也是大写需要判断这是连续缩写还是缩写结束、新词开始。当i 0且还有下一个字符时若下一字符不是大写也不是下划线例如FOMA场景里的倒数第二个大写字母才在此处补_。这一条正是处理SocialSecurityNumber→social_security_number这类连续缩写词的关键当前处于Lower或NewWord态前一个字符是小写或刚结束一个词直接补_例如IsMarried中M之前的那个_。随后把该大写字母转小写代码用char.ToLowerInvariant并保留了一个HAVE_CHAR_TO_LOWER_WITH_CULTURE条件编译分支用于文化敏感场景后追加状态切到Upper。遇到下划线s[i] _原样追加并回到Start态即原有的下划线不会被破坏。其他字符小写字母、数字等若处于NewWord态先补_然后原样追加状态切到Lower。对照示例 payload 的转换结果用示例中的属性名走一遍状态机可得原始属性名转换结果关键路径Namename单首字母大写无分支插入IsMarriedis_marriedM前状态为Lower插入_FOMAfoma全程Upper态下一字符均为大写不插_HighEmpathyhigh_empathyE前状态为Lower插入_SocialSecurityNumbersocial_security_numberS/N前状态为Lower插入_ecurit与umber交界处靠Upper分支的下一字符非大写规则补上最后一个_json-8 的 Benchmark 正是用这个输入做测试用例这个连续大写 小写收尾的边界规则正是朴素正则式拆分难以正确处理的场景也是移植 Newtonsoft 成熟实现而非简单Regex.Replace的原因。姊妹示例 json-8两种转换实现的 Benchmark 对比仓库中 json-8 专门对CamelCase 转 snake_case 的两种实现做了 Benchmark 对比与本示例算法直接相关第一种即上文这套来自 Newtonsoft.Json 的状态机实现在 json-8 的 Program.cs 中命名为ToSnakeCaseNewtonsoft第二种是一行 LINQ 实现public static string ToSnakeCaseLinq(string s) { return string.Concat(s.Select((x, i) i 0 char.IsUpper(x) ? _ x.ToString() : x.ToString())).ToLower(); }两种实现均用固定输入SocialSecurityNumber作为基准用例Program.cs#L108-L118。json-8 是基于 BenchmarkDotNetjson-8.csproj 中引用BenchmarkDotNet0.15.8的控制台应用运行方式为其 README 给出的两条命令dotnet build -configuration Release dotnet run从 json-8 的代码结构看这个对比的意义在于当命名策略被挂到JsonSerializerOptions上后ConvertName会在每次序列化时按属性调用算法本身的效率会体现在高吞吐 API 场景里。需要说明的是仓库中并未附带 Benchmark 的结果数据上述两种实现的取舍需读者自行按 json-8 的方法在本地运行验证。如何运行 json-7 并验证输出进入 projects/json/json-7 目录后dotnet run然后访问根路径/即可看到带缩进WriteIndented true的 JSON属性名和嵌套属性名均已是 snake_case 形态例如is_married、current_time、high_empathy。注意DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull的作用值为 null 的属性不会写入输出这与 json-2 的选项说明中IgnoreNullValues一项描述的行为对应。适用前提与注意事项该策略是全局生效于传入的JsonSerializerOptions的只要PropertyNamingPolicy挂上了SnakeCaseNamingPolicy同一 options 下所有对象属性包括嵌套对象都会按 snake_case 输出如需按接口或按端点差异化可在不同端点构造不同的JsonSerializerOptions如本示例所示在 handler 内构造。算法移植自 Newtonsoft.JsonToSnakeCase对空字符串直接原样返回且保留原有下划线因此对已是 snake_case 的输入基本是幂等的。适用框架前提示例目标为net10.0见 json-7.csproj由于JsonNamingPolicy与Results.Json均为较早期版本已具备的 API该思路在更早的 .NET 版本上同样适用仅 SDK 版本需与global.json的约束兼容。在 practical-aspnetcore 的 System.Text.Json 示例系列 中json-7 处于自定义命名策略这一环可与前序的 json-2JsonSerializerOptions 选项 和后序的 json-8snake_case 转换 Benchmark 对照阅读形成选项配置 → 自定义策略 → 性能对比的完整链路。赞分享示例工程【免费下载链接】practical-aspnetcorePractical samples of ASP.NET Core 11, 10, 9, 8.0, 7.0, 6.0, 5.0, 3.1, 2.2, and 2.1,projects you can use. Readme contains explanations on all projects.项目地址https://gitcode.com/gh_mirrors/pr/practical-aspnetcore点击查看免费下载相关推荐使用 System.Text.Json 的 JsonObject 构建 JSON 文档practical-aspnetcore 可写 JSON DOM 实战使用 System.Text.Json 的 JsonObject 构建 JSON 文档practical aspnetcore 可写 JSON DOM 实战示例工程practical-aspnetcore 实战用 JsonSerializerOptions 精细控制 System.Text.Json 的 JSON 输出practical aspnetcore 实战用 JsonSerializerOptions 精细控制 System.Text.Json 的 JSON 输出示例工程practical-aspnetcore 实战用 System.Text.Json 的 JsonArray 构建可写 JSON 文档Writable DOMpractical aspnetcore 实战用 System.Text.Json 的 JsonArray 构建可写 JSON 文档Writable DOM示例工程上一篇modetest 命令详解用 libdrm 模式测试工具验证 DRM/KMS 显示驱动linux-command 速查手册下一篇Apache Airflow 任务组拓扑排序优化pass-number 遍历如何消除反向声明 DAG 的 O(N²) 最坏情况创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Rainbond 仓库内嵌 etcd 运行时重配置设计解析:两阶段成员变更、法定人数保护与安全实践

Rainbond 仓库内嵌 etcd 运行时重配置设计解析:两阶段成员变更、法定人数保护与安全实践

云原生后端微服务DevOpsAI 应用 【免费下载链接】rainbond 无需学习 Kubernetes 的容器平台,在 Kubernetes 上构建、部署、组装和管理应用,无需 K8s 专业知识,全流程图形化管理 项目地址: https://gitcode.com/goodrain/rainbond …

2026/10/15 3:39:42 阅读更多 →
supabase-postgres-best-practices - conn-prepared-statements

supabase-postgres-best-practices - conn-prepared-statements

title: Use Prepared Statements Correctly with Pooling impact: HIGH impactDescription: Avoid prepared statement conflicts in pooled environments tags: prepared-statements, connection-pooling, transaction-mode 在连接池中正确使用预处理语句 预处理语句与单个数…

2026/10/15 3:38:42 阅读更多 →
OpenRig + DeepSeek 实战:手机BYOK AI对话客户端配置指南

OpenRig + DeepSeek 实战:手机BYOK AI对话客户端配置指南

最近我一直在手机折腾一件事:把DeepSeek这类开源大模型变成能随身带、随手用的日常工具。试了几个方案之后,OpenRig是目前唯一留在主屏幕上的那个。如果你还不清楚OpenRig是什么,简单说,它是一个跑在iOS上的AI对话客户端&#xff…

2026/10/15 3:38:42 阅读更多 →

最新新闻

如何判断Ubuntu是否真的关机?三路检查方法与实战探测脚本

如何判断Ubuntu是否真的关机?三路检查方法与实战探测脚本

你有没有遇到过这种情况:在终端里输入了sudo shutdown now,屏幕上日志飞快滚动,最后一切归于黑暗,风扇也慢慢停转,你很自然地认为这台 Ubuntu 机器已经关机了。但我在几年的实践中发现,这个结论经常下得太早…

2026/10/15 4:25:50 阅读更多 →
企业级升降平台选型指南:基于四大维度的实测横评与采购避坑要点

企业级升降平台选型指南:基于四大维度的实测横评与采购避坑要点

升降平台专业测评做了不少,但企业级采购的选型逻辑和普通短租完全是两码事。这次我们围绕安全、稳定、耐用、综合运维成本四大维度,对市面上主流升降平台做了连续三周的横向测评,最终一家此前不太张扬的厂商凭均衡表现登顶企业级推荐榜&#…

2026/10/15 4:25:50 阅读更多 →
设备资料包处理避坑指南:解压校验、固件版本核对与归档

设备资料包处理避坑指南:解压校验、固件版本核对与归档

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 4:25:50 阅读更多 →
插件加载失败与SDK版本查询超时:现代工具链插件机制排查指南

插件加载失败与SDK版本查询超时:现代工具链插件机制排查指南

1. 从“plugins”这个标题说起:它到底在聊什么“plugins”这个词,放在今天的开发语境里,早就不只是“插件”两个字那么简单了。你打开任何一个现代开发工具、编辑器、构建系统、甚至云平台的控制台,几乎都会看到它的身影。它背后代…

2026/10/15 4:25:50 阅读更多 →
Windows服务程序调试全攻略:从附加进程到控制台模式与日志排障

Windows服务程序调试全攻略:从附加进程到控制台模式与日志排障

Windows服务程序调试这件事,不少人都被它坑过。初次接触服务开发的人,可能第一反应是把服务项目跑起来、按F5直接进入断点,结果发现根本启动不了。哪怕是工作两三年的开发者,也时常在“服务启动后立刻停止”“日志没输出”“断点死…

2026/10/15 4:25:50 阅读更多 →
AI选品Agent全栈实战:用OpenClaw将跨境电商选品成功率从15%提升到42%

AI选品Agent全栈实战:用OpenClaw将跨境电商选品成功率从15%提升到42%

15%的选品成功率,意味着每选出100个品,最后能跑起来的只有15个,剩下85个全在库存积压和广告费里打水漂。这是跨境电商一个很扎心的平均数——不是某一家团队不行,是整个行业用“人工经验滞后数据”做选品,上限就摆在那…

2026/10/15 4:24:50 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →