我最近看过以下代码:
public class Person { //line 1 public string FirstName { get; } //line 2 public string LastName { get; } = null!; //assign null is possible public string? MiddleName {get; } = null; public Person(string firstName, string lastName, string middleName) { FirstName = firstName; LastName = lastName; MiddleName = middleName; } public Person(string firstName, string lastName) { FirstName = firstName; LastName = lastName; MiddleName = null; } }
基本上,我尝试挖掘c#8的新功能。其中之一是NullableReferenceTypes。实际上,已经有很多文章和信息。例如,这篇文章相当不错。但是我找不到有关此新声明的任何信息,null! 有人可以向我提供解释吗?为什么我需要使用这个?又什么区别line1和line2?
NullableReferenceTypes
null!
line1
line2
了解null!含义的关键是了解!操作员。您之前可能已将其用作“非”运算符。但是从C#8.0开始,该运算符还可以用于控制Nullabilty的类型
!
该!运算符用于某种类型时,称为Null宽容运算符 [ docs ]。它是在C#8.0中引入的
假设此定义:
class Person { public string? MiddleName; }
用法是:
void LogPerson(Person person) { Console.WriteLine(person.MiddleName.Length); // WARNING: may be null Console.WriteLine(person.MiddleName!.Length); // No warning }
此运算符基本上关闭编译器的空检查。
使用此运算符告诉编译器可以安全地访问某些可能为空的内容。您表示打算在这种情况下“不关心”空安全性。
谈论null安全性时,变量可以处于2种状态。
从C#8.0开始,默认情况下所有引用类型都是不可为空的。
可以通过以下两个新的类型操作符来修改“可空性”:
Nullable
Non-Nullable
?
这些运算符基本上是彼此对应的。编译器使用您使用这些运算符定义的信息来确保空安全性。
可空 string? x;
string? x;
x
x = null
不可为空 string y;
string y;
y 是引用类型-因此默认情况下不可为null。
y
y = null
string x; string? y = null;
x = y
Warning: "y" may be null
x = y!
法律!
y!
警告 的!操作者仅关闭在一个类型的系统级的编译器检查-在运行时,仍然值可以为空。
你应该 尝试 以 避免 使用!空赦的运营商。
在此操作员适合使用的情况下,存在有效的用例(在下面详细介绍),例如单元测试。但是,在99%的情况下,使用替代解决方案会更好。请不要!在您的代码中拍打几十个,只是为了使警告静音。考虑一下您的原因是否真的值得使用。
使用-但要小心。如果没有具体目的/用例,请不要使用它。
它抵消了编译器保证的空安全性的影响。
使用!运算符将很难发现错误。如果您有一个标记为不可为空的属性,则将假定您可以安全地使用它。但是在运行时,您突然碰到a NullReferenceException并挠头。由于在绕过带有的编译器检查之后,值实际上变为null !。
NullReferenceException
null
它告诉编译器这null不是一个null值。听起来很奇怪,不是吗?
与y!上面的示例相同。 因为您将运算符应用于null文字,所以它看起来很奇怪。但是概念是相同的。
public string LastName { get; } = null!;
该行定义了一个名为LastNametype 的不可为空的类属性string。由于它是不可为空的,因此从技术上讲,您不能为它分配null-显然。
LastName
string
但是,您只需要使用运算符就可以做到这一点-分配null给LastName- !。因为null!不是null- 就编译器所关心的null安全而言。