可空类型本质是nullable结构,int?与nullable完全等价;访问value前必须检查hasvalue,否则抛invalidoperationexception;??运算符仅提供默认值,不解决业务语义判断。

可空类型不是“加个问号就完事”,它直接决定你读数据库、处理 API 响应、做 UI 绑定时会不会在运行时炸掉。
int? 和 Nullable 是一回事,但写法影响可读性和一致性
两者完全等价:int? 是 Nullable<int></int> 的语法糖。编译后没区别,但实际编码中建议统一用 ? 后缀 —— 更短、更常见、IDE 支持更好。
-
int? age = null;✅ 推荐,符合 C# 习惯 -
Nullable<int> age = null;</int>⚠️ 可读性差,仅在泛型约束或反射场景下必要 - 别混用:一个项目里既写
DateTime?又写Nullable<datetime></datetime>容易让协作者困惑
访问 .Value 前必须检查 HasValue,否则必抛 InvalidOperationException
这是最常被忽略的崩溃点。很多人以为 if (x != null) 就够了,但 .Value 不吃这套 —— 它只认 HasValue。
-
int? x = null; int y = x.Value;→ 立刻抛出InvalidOperationException: Nullable object must have a value. -
if (x.HasValue) { Console.WriteLine(x.Value); }✅ 安全 -
if (x != null) { Console.WriteLine(x.Value); }⚠️ 表面上能过,但语义不清晰;.NET 6+ 编译器会警告“可能为 null” - 更稳妥的写法是用
GetValueOrDefault():它不抛异常,返回默认值(如0对应int?)
?? 运算符不是万能兜底,它只解决“null 时取默认值”,不解决业务逻辑分支
?? 是空合并运算符,用于提供 fallback 值,但它不会帮你判断“这个 null 到底是缺数据、还是故意留空、还是上游 bug”。
-
int? score = GetScore(); int finalScore = score ?? 0;→ 把缺失值强制转成 0,适合统计汇总 -
string? name = GetName(); string displayName = name ?? "未知用户";→ 对引用类型也有效(C# 8+ 启用可空引用类型后更关键) - ⚠️ 避免滥用:
var result = apiResponse.Data ?? new Data();可能掩盖数据为空的真实原因,不如先 log 或 throw - 注意优先级:
a ?? b + c等价于a ?? (b + c),不是(a ?? b) + c;复杂表达式务必加括号
数据库字段映射到 C# 时,int? 是标准做法,但 Entity Framework Core 有隐式陷阱
SQL Server 的 INT NULL 字段,对应 C# 必须是 int?;否则 EF Core 查询时遇到 NULL 会直接报错或静默截断。
- 实体类中写
public int? Age { get; set; }✅ 正确 - 写成
public int Age { get; set; } = 0;❌ 即使设了默认值,EF 仍会在 NULL 入库时赋 0,丢失原始语义 - EF Core 7+ 默认开启
nullable reference types,如果项目启用了<nullable>enable</nullable>,还要注意字符串字段是否声明为string?,否则迁移生成代码可能出错 - DTO 层别偷懒:不要把
int?直接暴露给前端,除非前端明确需要区分 “0”、“未填写”、“-1 表示无效”
真正难的不是写 ?,而是每次看到 int? 都得停下来想三秒:这个 null 是合法状态?要不要记录日志?下游系统能不能接受??? 给的默认值会不会误导业务判断?











