C# JSON序列化完整指南与常见问题解决方法
C# JSON序列化:那些看似“玄学”的问题,其实都有章可循

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
在C#里处理JSON,JsonSerializer.Serialize 或 JsonConvert.SerializeObject 这两行代码谁都会写。但真正让人头疼的,往往不是“怎么调”,而是那些藏在类型、配置、时区、命名规则里的细节。它们一旦对不上,轻则字段错位,重则数据丢失。下面这四大高频问题,几乎每个.NET开发者都会踩到。
System.Text.Json 默认驼峰命名、Newtonsoft.DateTime格式异常、字典键被改、long精度丢失是四大高频问题;需分别通过设置PropertyNamingPolicy=null、DateFormatHandling.IsoDateFormat、DefaultContractResolver、long转字符串解决。
System.Text.Json 默认驼峰命名导致字段名被改写
你有没有遇到过这种情况:明明在C#里定义的是 public string UserName { get; set; },序列化出去却变成了 "userName"?先别急着怀疑人生,这通常不是bug,而是特性在起作用。
从.NET 6开始,System.Text.Json 默认启用了 JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase。这个策略尤其在ASP.NET Core Web API中会自动生效,目的是为了迎合前端Ja vaScript社区的命名习惯。
- 先确认需求:如果你的服务是内部系统,或者主要对接前端,用驼峰命名大概率没问题。但如果是和Ja va、Python等其他后端服务互通,对方很可能期望的是PascalCase(即首字母大写),这时就需要关掉它。
- 如何关掉:很简单,
var options = new JsonSerializerOptions { PropertyNamingPolicy = null };就能让命名策略失效。 - 注意边界:这个设置只影响类的public属性名,默认不影响字典的key。除非你用的是.NET 7及以上版本,并且显式设置了
DictionaryKeyPolicy。 - 别混淆了:全局的
PropertyNamingPolicy和单个属性上的[JsonPropertyName("CustomName")]特性是两回事。后者的优先级更高,可以覆盖全局策略。
Newtonsoft.Json 序列化 DateTime 输出 /Date(1234567890000)/ 格式
如果你还在用Newtonsoft.Json(即Json.NET),可能会发现序列化出来的时间戳长这样:/Date(1234567890000)/。这是库默认使用 Ja vaScriptDateTimeConverter 的结果,一种比较古老的格式。现代的API接口基本已经不认这种格式了,前端解析时要么失败,要么时间错乱。
- 强制使用ISO标准格式:最直接的解决方法是配置序列化设置:
new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.IsoDateFormat }。这样输出的就是"2023-10-27T10:30:00Z"这种通用格式。 - 时区问题不能只靠配置:如果服务端明确要求UTC时间,千万别只依赖这个配置。务必在序列化前,对DateTime对象调用
.ToUniversalTime()。否则,本地时区的时间会被直接当成UTC时间写进去,造成误解。 - 自定义格式更稳妥:对于有固定格式要求的场景,可以设置
DateFormatString = "yyyy-MM-dd HH:mm:ss"。但要注意,这个设置只在DateFormatHandling = DateFormatHandling.Custom时才会生效。 - 避免配置冲突:别在同一个属性的头上既标记了
[JsonConverter(typeof(DateTimeConverter))],又在全局配置里配一遍,这样很容易导致行为不一致。
序列化 Dictionary 后键名丢失或全小写
字典序列化后,发现key的名字变了,甚至全变成小写了?别慌,数据没丢,是序列化库的默认策略在“动”你的key。
这里有个关键区别:System.Text.Json 默认会保留字典键的原样;而 Newtonsoft.Json 的行为则严重受 ContractResolver 影响。
- 检查Newtonsoft的解析器:如果你用了
CamelCasePropertyNamesContractResolver,那要注意了,它不仅会把属性名改成驼峰,字典的key也会被一并改造。 - 锁死原始键名:在Newtonsoft中,想保持key不变,可以使用默认的解析器:
new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() }。 - System.Text.Json的版本陷阱:在.NET 6及以后版本,如果你启用了全局的
PropertyNamingPolicy(比如驼峰),那么字典的key也会被影响而改变。这一点在早期版本中是不会发生的,非常容易忽略。 - 警惕嵌套序列化:如果字典的value是匿名对象或者动态的
JObject,要确保它本身没有被二次序列化。一个常见的坑是:JsonConvert.SerializeObject(new { data = JObject.Parse(json) }),里面的JObject可能已经被处理过一次了。
序列化 long 类型 ID 到前端时精度丢失
这是前后端联调时的一个经典“惨案”。C#里的 long 类型(Int64)最大值可以达到 2^63 - 1,常用于生成雪花ID等大数字。但Ja vaScript的 Number 类型,其最大安全整数是 2^53 - 1。一旦超过这个范围,数字传到前端就会精度丢失,变成一串奇怪的尾数。
- 根本解法:转成字符串:必须把long类型的值,在序列化阶段就转换成字符串。不要指望前端用
parseInt去补救,那为时已晚。 - Newtonsoft的解决方案:推荐编写一个自定义转换器。继承
JsonConverter,然后重写WriteJson方法,在里面调用writer.WriteValue(value.ToString())即可。 - System.Text.Json的解决方案:思路类似,继承
JsonConverter,实现对应的Write方法。最后记得在JsonSerializerOptions里通过options.Converters.Add(new LongToStringConverter())注册这个转换器。 - 格式化不是关键:别纠结于用
ToString("D")还是其他数字格式,只要最终输出的JSON值是带引号的字符串(如"id": "1234567890123456789"),前端就能无损接收。
最后,还有一个最常被跳过的环节:序列化后的校验。代码跑通了,不代表JSON就对了。在把数据发出去之前,不妨先用 JsonDocument.Parse(json) 快速验证一下结构,或者扔到在线JSON格式化工具里看一眼。很多时候所谓的“序列化失败”,其实是上游数据拼接时字符串就错了,问题根本不在序列化逻辑本身。
相关攻略
如何在Perplexity中实现JSON Schema约束响应:五种实用方法 想要让AI聊天助手Perplexity严格按照你定义的数据结构来输出答案吗?这就像给一个思维活跃的助手一份精确的图纸,要求它按图施工。JSON Schema正是这份图纸,它能明确规定响应中必须包含哪些字段、每个字段是什么类
如何自定义 Go 结构体字段的默认序列化命名规则(JSON BSON) 在 Go 语言中,结构体字段进行 JSON 和 BSON 序列化时,默认行为是将 PascalCase 转换为 snake_case 或保持原名。开发者无法全局修改这一默认规则,必须通过结构体标签进行显式声明。对于追求高效和整洁
如何自定义 Go 结构体字段的默认 JSON BSON 字段名映射规则 在 Go 语言开发中,结构体字段的 JSON 和 BSON 序列化默认遵循特定的命名转换规则。然而,这套默认行为往往无法满足项目对统一命名风格(如小写驼峰命名法)的全局需求。开发者要么需要为每个字段手动添加标签,要么就需要借助代
如何优雅处理 JSON 中同一字段时而为对象、时而为数组的 Go 解析难题 在对接不规范 REST API 时,开发者常面临同一 JSON 字段(例如 “line”)在不同响应中动态变化,时而为单个对象,时而为对象数组,导致标准 Go 结构体反序列化失败。本文将深入解析如何通过 json RawMe
应对JSON字段类型飘忽不定:Go中的灵活解析策略 在对接第三方API时,开发者们常常会遇到一个令人头疼的设计:同一个JSON字段,其数据类型居然会“变脸”。比如,一个名为line的字段,在返回单条记录时是个对象({ }),而在返回多条记录时却摇身一变,成了对象数组([ ])。这种反模式设计
热门专题
热门推荐
Poe交换机带载后重启:是故障,还是系统在“自救”? 不少朋友遇到过这个头疼的问题:PoE交换机一接上设备就重启。其实,这本质上不是设备坏了,而是供电系统一套精密的自我保护机制在起作用。当负载接入的瞬间,如果系统检测到功耗超标、供电不稳等情况,就会主动触发复位,防止硬件受损。这正是IEEE 802
高性价比电饼铛:精准匹配、扎实可靠、真正省心 挑选一款高性价比的电饼铛,核心其实很明确:功能要精准匹配你的真实需求,材质工艺必须扎实可靠,细节设计能让你每天用着都省心。它追求的绝不是单纯的便宜或者参数漂亮,而是每一分钱都花在刀刃上。比如,2100W级的稳定火力保证了煎烤效率不打折;0氟不粘涂层配合蜂
红米K30 5G动态壁纸联网机制全解析 关于红米K30 5G的动态壁纸是否需要一直联网,答案是:完全没必要。这玩意儿用起来其实很“懂事”,它只在你第一次上手和偶尔想换新的时候,才需要网络搭把手。 其背后的逻辑很清晰:手机搭载的MIUI系统,把所有酷炫的动态壁纸资源都放在了小米官方的“云端仓库”里。所
vivo Y35桌面时间不显示?别急,这事儿有解 不少vivo Y35用户可能都遇到过这个情况:一觉醒来,或者换个主题之后,主屏幕上那个熟悉的“时间”不见了。先别急着怀疑手机坏了,事实是,超过八成的类似问题,根源其实很简单——时间组件压根没被“请”上桌面,或者相关的自动设置被无意中关闭了。作为一台搭
英雄联盟手游杰斯新皮肤外观设计酷炫,充满科技感。技能特效以蓝色能量为主,视觉效果震撼且辨识度高。实战中技能清晰、手感流畅,能提升操作自信与战场表现。整体而言,该皮肤在视觉、特效与实战体验上均表现优异,值得玩家入手。





