做电商、金融、支付、ERP,金额类型一错,全线埋雷。
在 .NET 里,金额用 long 还是 decimal ,不是习惯问题,是架构规范 + 安全底线。
这一篇讲清楚:什么时候用、为什么、怎么用才最稳。
一、先给结论(直接背)
- 系统内部计算、业务逻辑、展示:统一用 decimal
- 对接支付、第三方接口、存储分:建议用 long(以分为单位)
- 永远不要用 float / double 存金额
一句话口诀:
对内 decimal,对外 long;业务看元,交互看分。
二、为什么绝对不能用 float/double?
因为二进制浮点数不能精确表示 0.1、0.2 这类十进制小数。
你写:
csharp
double a = 0.1;
double b = 0.2;
if (a + b == 0.3) // 结果:false
实际结果是:
plaintext
0.30000000000000004
金融系统敢用浮点数,上线即事故。
三、decimal:.NET 专为钱设计的类型
decimal 是十进制高精度类型,天生为金融、金额而生。
优点
- 精度极高,计算无误差
- 代码直观: 10.99m 就是 10 元 9 角 9 分
- 支持加减乘除、税率、折扣、分摊、利息
- 与数据库 decimal(18,2) 完美对应
适用场景
- 订单金额、优惠、运费、税费计算
- ERP、财务、进销存、工资、结算
- 所有业务层、领域层、DTO、展示
企业级写法
csharp
public class Order
{
public int Id { get; set; }
public decimal TotalAmount { get; set; } // 总金额
public decimal Discount { get; set; } // 优惠
public decimal PayAmount { get; set; } // 实付
}
只要是你自己系统内部,无脑 decimal 绝不会错。
四、long:什么时候才用?(存分)
long 是64 位整数,用来存分:
- 1 元 = 100 分 → 存 100
- 9.99 元 → 存 999
适用场景
- 对接微信支付、支付宝、云闪付
- 跨系统、跨语言接口(Java/Go 前端)
- 对精度极度敏感的结算、记账
- 历史老系统统一以分为单位
优点
- 完全无精度问题
- 传输、存储、序列化极稳
- 所有系统都能看懂
缺点
- 代码不直观:看到 39900 要反应一会是 399 元
- 业务计算要不停 ×100 ÷100
五、真实架构最佳实践(大厂标准)
1. 数据库
- 推荐:decimal(18,2)
- 特殊场景:bigint(存分)
2. 后端代码
- 实体、领域、服务层:decimal
- 对接支付工具:转 long(分)
3. 接口交互
- 内部接口:decimal
- 外部支付接口:long(分)
4. 工具类封装(必写)
csharp
public static class MoneyUtil
{
// 元 → 分
public static long YuanToFen(decimal yuan)
=> (long)(yuan * 100);
// 分 → 元
public static decimal FenToYuan(long fen)
=> fen / 100m;
}
六、一张表看懂怎么选
场景 类型 理由
业务逻辑、计算 decimal 直观、安全、无精度问题
展示、前端、报表 decimal 直接用,不用换算
订单、优惠、结算 decimal 金融级标准
对接支付第三方 long 行业统一规范(存分)
跨系统传输 long 无歧义、不丢精度
工资、财务、记账 decimal 合规、易审计
七、最终总结(面试必背)
1. 金额禁止 float/double
2. 内部业务全用 decimal
3. 支付交互统一用 long(分)
4. 封装工具类做元分互转
一句话:
业务看钱用 decimal,交互转账用 long。
在 .NET 里,把金额类型用对,
你就已经避开了 90% 的金融线上事