C# 8 - Nullable Reference Types 可空引用类型
在写C#代码的时候,你可能经常会遇到这个错误:
但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作。
可空引用类型 Null Reference Type
所以,C# 8的可空引用类型就出现了。
C# 8可以让你在编译时就避免null引用错误,它并不是把null值从代码里移除了,而是它可以让你表达意图。具体的做法就是你可以告诉编译器哪个引用可能是null的,而哪些引用不可能是null。
看下面这个例子:
O references
PrintPerson(Person person)
public static void
Console . WriteLine(person.Name);
很显然,我们期待person这个参数它不可以是null的。
但是在C# 8之前,如果我们这样调用该方法,那么在编译时是不会报错的:
null;
Person person
PrintPerson(person);
而如果运行程序,那么结果就是:
Console . WriteLine(person . Name);
class Person
•son = null
Exception Unhandled
System.NullReferenceException: 'Object reference not set to an
LIC
LIC
string Name {
{ get;
int
Age
get;
set;
set;
instance of an object.'
person was null.
View Details Copy Details
Exception Settings
Start Live Share session...
打开null检查
而在Visual Studio 2019里面(C# 8的项目),修改项目文件,添加null检查之后:
'
Exe
netcoreapp3. R/ Target Framework>
PropertyGroup>
PropertyGroup>
null; ,
Person person
PrintPerson(Eä2Q);
这里就会出现警告。
例子:
有两个类,Person类的Address属性的类型是另外一个类:
2 references
public class Person
O references
{ get; set; }
public string
Name
I reference
Address { get; set;
public Address
I reference
public class Address
I reference
public string Province { get; set;
O references
{ get; set; }
public string
现在可以看到,这些属性都出现了波浪线的警告,如果我们build一下这个项目,那么也会出现很多警告:
Show output from: Build
' •n 'void printperson(person
Rebuild All
starte
c: (30,
1>Pro
c: (31,
1>Pro
c: (24,
1>Pro
c: (25,
1>Pro
cs(ll,
1>Pro
cs(12,
1>Pro
n: 1 Appl —
1>C0
ne building
Rebul
23, 30, 31)
23, 31, 27)
23, 24, 27)
24, 25, 31)
29, 11, 33)
25, 12, 31)
warm
warm
warm
warm
warm
warm
d project: ConsoleÅppl,
ng CS8618:
ng CS8618:
ng CS8618:
ng CS8618:
ng cs8600:
ng CS8604:
guy at 1 on:
ble property '
ble proper
ble proper
ty
ble proper
ty
Debug
k-,y CPU
ci ty'
e
Address' is
s 'minitialized C n
s 'minitializeå
s 'minitializeå
'minitialized C n
for
Consi der
to non—null a
1 ill
r declaring the
declaring the pr
C n d declaring the pr
r declaring the
ble type
property as null able
operty as nullablæ
operty as nullablæ
property as null able
Converting null lit al or possible null due
\Cons01eÅppl 0\Conso e
project "ConsoleÅppL c
'Id All: 1
这是因为我们把这两个类的成员声明称了非null的引用类型,而我却没有对它们进行初始化。
成员可能是null的
如果我想让这些成员可以为null(意图上),那么就需要把它们设置为可null的(意图),在类型后边加上问号“?”即可:
2 references
public class Person
O references
{ get;
public string?
Name
I reference
public Address? Address {
I reference
public class Address
I reference
public string? Province {
O references
City
public string?
get;
set; }
get; set;
get; set;
set;
再次build项目之后,警告都没有了:
Show output from: Build
Rebuild started: projec
I >Cons01eÅppl —
Rebuild All: 1 succeeded,
ConsoleÅppl,
gurati on:
Debug kny CPU
\Cons01eÅppl nso e
0 1 ill
然后再看一下这个方法:
O references
Print(Person person)
public static void
Console . WriteLine(person.Name);
Console . WriteLine( . Province) ;
这里person.Address.Province有一个警告,是因为Address可能是null。
可以有几种办法把这个警告去掉,首先是使用null条件操作符:
如果是Address是null的话,就输出null。
或者,如果你确认Address属性不会是null,那么可以在Address后添加一个叹号”!“,表示Address肯定不是null:
Console .WriteLine(person .Address ! . Province) ;
这个叹号的作用仅仅是去掉了警告,它没有改变任何运行时的状况,如果Address为null,那么这句话仍然会抛出NullReferenceException。
所以,只有确认我们访问的东西肯定不是null的时候,才应该使用"!"。
成员不可能是null
下面我更改一下思路意图,假设所有的成员都不可能为null,那么修改两个类:
类成员又出现了警告。
而回到方法里,我把叹号和问号都去掉之后,也不会出现警告了,因为它认为所有的成员都不会是null了:
但是还要记住,这个只是在编译时进行的检查,如果成员为null,还是会抛出异常的。这种操作对于运行时来说没有任何改变。
解决成员上出现的警告
使用构造函数对成员初始化,可以去掉这些警告:
另外一种办法就是直接对属性进行初始化:
我们还是采用构造函数初始化的办法吧。
往构造函数里传递null
那么往构造函数里面传递null会出现什么情况呢?试一下:
提示还是比较智能的,有警告,它说无法把null这个字面值转化为非null的引用类型。
另一种开启nullable检查的方式
如果把老项目的项目文件直接添加以下内容:
那么项目在编译的时候很可能出现大规模的问题。
所以一点一点启用nullable检查是比较好的做法。
首先我把项目文件恢复原状,然后打开某个文件,在文件最上面添加以下内容:
然后在文件的最下面添加:
这样的话,这个文件里面所有的内容都开起了nullable检查。
或者,我们也可以只针对一段代码进行检查:
博客文章可以转载,但不可以声明为原创.
我的.NET Core公众号:
https://www.cnblogs.com/cgzl/p/11665814.html