C# 学习笔记 21:驾驭虚无的力量—— Null 与可空类型 (Nullable)
开篇:皮皮的“空背包”悖论
皮皮(Pipi)正在开发玩家的装备栏。
装备栏有 5 个格子,他用一个整数来表示物品 ID:
int slot1 = 0;
但他很快发现了致命问题:
❗ 物品 ID = 0 是「新手木剑」❗ 那“空格子”不就变成白送武器了?
于是他改成:
int slot1 = -1;
皮皮犹豫了:
“虽然能用,但这种 -1 是啥? 我以后会不会忘?”
瓜瓜点评:
“这就是魔法数字(Magic Number)!”
在编程世界里:👉 “无”不应该伪装成某个值👉 “无”就应该是—— null
第一关:什么是 Null?(引用类型)
在之前的学习中我们知道:
class 是引用类型
变量本质是:
🔑 一把“钥匙”,指向堆内存中的对象
两种状态
// ✅ 有对象(钥匙有门)Monster boss = new Monster();// ❌ 没对象(钥匙没门)Monster emptyMonster = null;
经典爆炸:空引用异常
Monster m = null;Console.WriteLine(m.Name);
结果:
☠️ NullReferenceException
本质
你拿着一把“没有对应门的钥匙”去开门

第二关:值类型的困境
皮皮尝试:
int slot1 = null;
结果:
❌ 编译失败
为什么?
因为:
都是 值类型(Value Type)
本质理解
值类型就像:
📝 一张必须写内容的便利贴
它不能是:
❌ “不存在的便利贴”
第三关:神奇问号 —— T?
为了解决这个问题,C# 提供了:
可空类型(Nullable)
用法
int? slot1 = null; // ✅ 真正的“空”int? slot2 = 105; // ✅ 也可以正常存值
底层理解:薛定谔的盒子
int? 本质上是:
一个“可能有值,也可能没有”的盒子
使用方式
int? damage = null;if (damage.HasValue){ Console.WriteLine(damage.Value);}else{ Console.WriteLine("没有伤害");}
第四关:防爆降落伞 —— ?.
以前我们要写:
if (player != null){if (player.Weapon != null) { player.Weapon.Attack(); }}
现在只要一行
player?.Weapon?.Attack();
翻译一下
如果不是 null → 继续如果是 null → 立刻停止(不报错)
效果

第五关:备胎操作符 —— ??
当值为 null 时,我们常常需要一个默认值。
传统写法
string finalName = (savedName != null) ? savedName : "神秘人";
简化写法
string finalName = savedName ?? "神秘人";
语义
用左边 如果是 null → 用右边
终极连招:?. + ??
string guildName = player?.Guild?.Name ?? "散人玩家";
一句话解释
安全访问 + 默认值兜底

阅读方式
player 不存在 → null↓Guild 不存在 → null↓Name 不存在 → null↓最终 → 用 "散人玩家"
今日战利品
| | | |
|---|
null | | | string s = null; |
T? | | | int? id = null; |
?. | | | player?.Attack(); |
?? | | | name ?? "未知" |
课后思考
bool?
可以表示几种状态?
提示: 普通 bool:
true / false
那加上 null 呢?
👉 这在数据库“未选择状态”中非常常见。
下期预告
皮皮在学习 Unity 时发现一个诡异现象:
[SerializeField]privateint hp;
这个 private 变量:
居然出现在 Unity 面板里了?!
皮皮震惊:
“这既不是方法,也不是赋值, 只是头上戴了个‘帽子’,就有超能力?”
下一期,我们将进入真正的进阶领域:特性(Attribute)与反射(Reflection)