CodeGym /课程 /C# SELF /Nullable Reference Types简介

Nullable Reference Types简介

C# SELF
第 14 级 , 课程 1
可用

1. NullReferenceException的问题

基本上每个刚学C#的(甚至老手)程序员都遇到过这个吓人的提示:


System.NullReferenceException: 对象引用未设置为对象的实例。

来,经典场景:

string hello = null;
Console.WriteLine(hello.Length); // 砰! NullReferenceException

意思很简单:你想访问一个根本不存在的对象。也就是说变量指向了null——就是啥都没有。

为啥这种错误容易犯?

因为C#里大多数引用类型历史上都能赋值为null。程序员经常忘了检查变量到底是不是指向了对象,结果就中招,遇到著名的NullReferenceException

如果每遇到一次NullReferenceException都能拿一美元,估计早就写出自己的操作系统了。

为啥这是个问题?

以前我们学过怎么让int?或者double?这种值类型能等于null——比如数据库字段没填的时候,明确表示“没有值”。

但引用类型(比如string、各种class、数组啥的)一直都能等于null。C#从一开始就是这样。方便归方便,但也危险——因为语言不会强制你去想“这个引用会不会是空的?”

2. 进化:Nullable Reference Types(NRT)

五年前,C#引入了一个新特性,直接颠覆了对抗NullReferenceException的思路——Nullable Reference Types(NRT)。

string s = "hello";   // 非nullable引用
string? maybe = null; // nullable引用
非nullable和nullable引用类型的区别

核心思想:

  • 严格区分那些绝对不能null的引用变量,和那些可以为空的引用。
  • 让程序员在编译阶段就能看到null相关的潜在问题,而不是等到运行时才发现(那就晚了)。

新版C#里,声明引用变量的方式变了:默认不能直接赋null,除非你明确允许。

就这么一个?,变量的意义立马变了!

3. 开启Nullable Reference Types

默认情况下,这种严格语法是关闭的,为了兼容老代码。但现在Visual Studio、Rider和.NET CLI的新项目模板都已经默认开启NRT——或者至少强烈建议你这么做。

想知道你的项目有没有开NRT,去.csproj文件里找这行:

<Nullable>enable</Nullable>
在项目里开启NRT

没有的话可以手动加上——很安全。

对代码有啥影响?

  • 如果NRT没开(老行为):string s = null;——没报错,大家都无所谓。
  • 如果开了:编译器会警告你,不能把null塞进不该为null的变量。

4. NRT的例子

简单例子


#nullable enable // 这行代码为当前文件开启NRT检查

string notNullable = "你好";
string notNullable2 = null; // 编译错误!
string? nullableString = null; // 没问题,我们明确允许null
严格 null检查的例子

第一行声明了一个永远要指向真实对象的字符串。
第三行声明了一个可以为null的字符串。

检查null

void PrintLength(string? s)
{
    // 编译器会警告你:“如果s == null咋办?”
    Console.WriteLine(s.Length); 
    
    // 这样就OK
    if (s != null)
    {
        Console.WriteLine(s.Length); 
    }
}

编译器现在会提醒你别忘了检查!

编译器警告

如果你无视警告,直接访问nullable变量——编译器会给你个新(而且很有用!)的警告。不是错误(程序还能编译),但会有个黄灯提醒你:“你确定吗,兄弟?”

对比不同模式:

C#类型 能为null吗? 传统模式(NRT前) NRT模式(#nullable enable
int 不能 不能 不能
int?
string 不能(一直都能) 不能(默认不行)
string? 不能

5. 建议:NRT怎么用、为啥用

  • 减少bug:少了null导致的莫名其妙崩溃,开发者和用户都开心。
  • 代码更清晰:一眼就能看出哪里可能是空,哪里必须有值。
  • 编译器帮忙:承认吧,编译器真的很努力!NRT警告是发现潜在bug的宝藏。

哪些场景必不可少

  • 大项目,很多人一起写代码。
  • API和公共库——让别人一看就知道能干啥不能干啥。
  • 对可靠性要求高的地方(比如银行app、医疗系统啥的)

6. 常见错误和小陷阱

  • “忘了加?
    给普通字符串赋nullstring s = null;)——编译器会警告你,因为现在默认普通字符串不能为null
  • “乱用?
    所有变量都写成string?,只为了让编译器不警告。其实应该仔细标注,哪里才真的允许为空。
  • “误解警告”
    忽略警告,结果在以为编译器会帮你兜底的地方还是遇到NullReferenceException
2
任务
C# SELF, 第 14 级, 课程 1
已锁定
声明 Nullable Reference Types
声明 Nullable Reference Types
2
任务
C# SELF, 第 14 级, 课程 1
已锁定
空值检查
空值检查
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION