1. 问题现象与背景解析
最近在调试一个C#项目时遇到了一个让人头疼的JSON解析错误:"JsonException: Can't assign value 'xxx'(type System.Double) to type System.Int64 at LitJson.JsonMapper"。这个错误发生在使用LitJson库进行JSON数据反序列化时,表面上看是类型不匹配的问题,但背后其实隐藏着几个值得深入探讨的技术点。
LitJson是一个轻量级的C# JSON处理库,以其简单易用和高性能著称。它通过JsonMapper类提供序列化和反序列化功能,但在处理数值类型时却可能出现这种看似简单却容易让人困惑的类型转换异常。这个错误的核心在于:JSON中的数字值被解析为System.Double类型,而目标字段却是System.Int64类型,导致赋值失败。
在实际开发中,这种情况经常出现在以下场景:
- 从第三方API接收的JSON数据中包含浮点数,但本地模型定义为整型
- 数据库查询结果经过JSON序列化后,数值精度发生变化
- 不同系统间通过JSON交互时对数值类型的约定不一致
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 错误根源深度剖析
2.1 LitJson的类型处理机制
LitJson在处理JSON数值时有一个特点:它会将所有JSON数字默认解析为Double类型。这是由JSON规范本身的特点决定的 - JSON不区分整数和浮点数。当遇到像{"value":123.45}或{"value":123}这样的数据时,LitJson会统一将它们解析为Double。
问题出现在反序列化阶段。如果我们有一个这样的C#类:
csharp复制public class MyData {
public long value { get; set; }
}
然后尝试反序列化包含"value":123.45的JSON时,LitJson会尝试将Double类型的123.45赋值给Int64类型的value字段,这时就会抛出我们看到的异常。
2.2 类型系统的差异
这里涉及到几个关键的类型系统差异:
- JSON本身没有整数和浮点数的区分
- C#有严格的类型系统,Int64和Double是不同的类型
- 隐式类型转换规则:C#允许从Int64到Double的隐式转换,但不允许反向转换
LitJson的这种设计选择有其合理性 - 使用Double可以保证不丢失任何数值信息。但这也带来了我们遇到的类型不匹配问题。
3. 解决方案与实现细节
3.1 临时解决方案:修改JSON数据
最直接的解决方法是确保JSON数据中的数值与C#模型中的类型匹配:
- 如果目标字段是long/int,确保JSON中是整数(不带小数点)
- 如果JSON中有小数,将C#模型中的对应字段改为double/decimal
csharp复制// 修改后的模型
public class MyData {
public double value { get; set; } // 改为double类型
}
注意:这种方法适用于你能控制数据源的情况。如果是第三方API,可能无法保证数据格式。
3.2 使用自定义JsonMapper设置
LitJson提供了自定义类型转换的机制。我们可以注册一个自定义的包装器来处理类型转换:
csharp复制JsonMapper.RegisterImporter<double, long>((double value) => {
return Convert.ToInt64(value);
});
// 现在可以正常反序列化了
var data = JsonMapper.ToObject<MyData>(jsonString);
这种方式的优点是:
- 全局生效,一次注册到处使用
- 可以精确控制转换逻辑(如四舍五入或截断)
- 不影响原有模型定义
3.3 更健壮的解决方案:自定义JsonWrapper
对于更复杂的情况,可以实现一个自定义的JsonWrapper:
csharp复制public class SafeJsonMapper {
public static T ToObject<T>(string json) {
try {
return JsonMapper.ToObject<T>(json);
} catch (JsonException ex) {
if (ex.Message.Contains("Can't assign value")) {
