—— 数据精度保卫战中的checked与unchecked秘籍
📌 核心概念速览
1. 隐式转换
- 自动发生,无数据丢失风险(如
int
→long
) - 遵循"小类型→大类型"路径(见下图⬇️)
[图1:C#隐式数字转换路径 | 箭头方向为安全转换路径]
2. 显式转换
- 需强制类型声明(如
(int)3.14
) - 可能导致数据截断或溢出(如
long
→int
)
️ 溢出检测:程序安全的守门人
默认情况下,C#处于 unchecked
上下文(不检测溢出)。需主动启用安全检测:
操作方式 | 语法示例 | 作用 |
---|---|---|
运算符 | checked(expr) | 单表达式溢出时抛OverflowException |
语句块 | checked { ... } | 整段代码启用溢出检测 |
禁用检测 | unchecked(expr) | 强制忽略溢出(结果可能异常) |
// 经典案例对比
ushort sh = 2000;
byte sb;// 不检测:丢失高位字节 → 输出208
sb = unchecked((byte)sh); // 检测:溢出时崩溃 → 抛出OverflowException
sb = checked((byte)sh);
💡 嵌套技巧
checked
与unchecked
可多层嵌套,精准控制风险范围:
checked {unchecked { /* 此处允许溢出 */ } checked { /* 此处严格检测 */ }
}
🔁 显式转换的六大雷区与应对策略
1. 整数 → 整数
- ✅
unchecked
:直接截断高位(如0x1234
→0x34
) - ❌
checked
:溢出必抛异常
2. 浮点 → 整数
- 小数部分无条件截断(3.99 → 3)
- ⚠️ 超范围时:
```mermaidgraph LRA[值超出目标范围] --> B{checked?}B -->|Yes| C[抛OverflowException]B -->|No| D[结果未定义!]```
3. decimal → 整数
- 任何超范围转换 → 必抛
OverflowException
(无unchecked
豁免权!)
4. double → float
- 值过小 → 归零
- 值过大 → ±∞(正/负无穷大)
5. 浮点 → decimal
- 值过小 → 归零
- 值过大 → 立即抛异常
6. decimal → 浮点
- 永远成功,但可能损失精度(decimal精度高于float/double)
[图2:显式数字转换规则矩阵 | 展示各类型转换风险点]
[图3:浮点转整数流程示意图 | 突出截断与溢出逻辑]
💎 最佳实践总结
1. 默认策略
- 生产环境建议全局启用
checked
,在Program.cs
中添加:Checked.Enable(); // .NET 6+全局启用检测
2. 性能敏感场景
- 在确定性无溢出区块使用
unchecked
提升性能(如加密计算)
3. 浮点转换黄金法则
// 先检查范围再转换
double d = 1e20;
if (d >= float.MinValue && d <= float.MaxValue)
{float safeFloat = (float)d;
}