isx*_*ker 56 c# c#-8.0 nullable-reference-types
我最近看到了以下代码:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
基本上我试着深入研究新的c#8功能.其中之一是NullableReferenceTypes.实际上已经有很多关于它的文章和信息.例如,这篇文章非常好.但是我找不到关于这个新陈述的任何信息null!
有人可以向我提供解释吗?为什么我需要使用它?又什么区别line1和line2?
Pat*_*eck 72
null!在类型上使用时操作符是什么?!当在类型上使用时,运算符称为Null Forgiving Operator [ docs ].它是在C#8.0中引入的
假设这个定义:
class Person
{
public string? MiddleName;
}
Run Code Online (Sandbox Code Playgroud)
用法是:
void LogPerson(Person person)
{
Console.WriteLine(person.MiddleName.Length); // WARNING: may be null
Console.WriteLine(person.MiddleName!.Length); // No warning
}
Run Code Online (Sandbox Code Playgroud)
该运算符基本上关闭编译器空检查.
使用此运算符告诉编译器可以安全访问的内容.在此实例中,您表达了"不关心"null安全性的意图.
在谈论无效安全时,变量可以有两种状态.
由于C#8.0默认情况下所有引用类型都是非可空的.
这两个新的类型运算符可以修改"可空性":
!=从!到!Nullable=从Non-Nullable到?这些运营商基本上是彼此的对应物.编译器使用您使用这些运算符定义的信息来确保空安全性.
Non-Nullable 操作员用法.可空 Nullable
? 是一个引用类型 - 所以默认情况下不可为空.string? x;运算符 - 这使其可以为空.x 工作良好.非空的 ?
x = null 是一个引用类型 - 所以默认情况下不可为空.string y; 生成警告,因为您将空值分配给不应为null的内容.y 操作员用法.string x;
string? y = null;
Run Code Online (Sandbox Code Playgroud)
y = null
!x = y
Warning: "y" may be null应用x = y!运算符以y!使其不可为空.警告的
!操作者仅关闭编译器检查在一个类型的系统级-在运行时,仍然值可以为空.
你应该尝试以避免使用y空赦的运营商.
有一些有效的用例(下面详细介绍),例如单元测试,这个操作符适合使用.在99%的情况下,您最好使用替代解决方案.请不要!在你的代码中打几十个,只是为了使警告静音.想想你的事业是否真的值得使用.
使用 - 但要小心.如果没有具体目的/用例不喜欢不使用它.
它否定了编译器保证的null安全性的影响.
使用!运算符将很难找到错误.如果您有一个标记为不可空的属性,您将假设您可以安全地使用它.但是在运行时,你会突然陷入!困境.由于在绕过编译器检查后,值实际上变为null !.
NullReferenceException.!意味着什么?它告诉编译器null不是null!值.听起来很奇怪,不是吗?
它与null上面的例子相同.由于您将运算符应用于null文字,因此它看起来很奇怪.但这个概念是一样的.
public string LastName { get; } = null!;
Run Code Online (Sandbox Code Playgroud)
该行定义了一个名为y!type 的非可空类属性null.因为它是不可空的,所以从技术上讲,你不能为它指定null - 显然.
但是你通过使用LastName运算符来做到这一点.因为string不是null - 只要编译器关注null安全性.
Qwe*_*tie 27
null!用于将 null 分配给不可为 null 的变量,这是一种承诺该变量null在实际使用时不会为 null 的方法。
我将null!在 Visual Studio 扩展中使用,其中属性由 MEF 通过反射初始化:
[Import] // Set by MEF
VSImports vs = null!;
[Import] // Set by MEF
IClassificationTypeRegistryService classificationRegistry = null!;
Run Code Online (Sandbox Code Playgroud)
(我讨厌变量如何在这个系统中神奇地获取值,但事实就是如此。)
我还在单元测试中使用它来标记由设置方法初始化的变量:
public class MyUnitTests
{
IDatabaseRepository _repo = null!;
[OneTimeSetUp]
public void PrepareTestDatabase()
{
...
_repo = ...
...
}
}
Run Code Online (Sandbox Code Playgroud)
如果在这种情况下不使用null!,则每次读取变量时都必须使用感叹号,这将是一种麻烦,没有任何好处。
注意:好主意的情况null!相当罕见。我将其视为最后的手段。
Jul*_*eur 11
当打开"可空引用类型"功能时,编译器会跟踪它认为代码中的哪些值可能为null.有时编译器可能没有足够的知识.
例如,你可以使用延迟初始化模式,其中的构造不符合实际的(非空)值初始化所有字段,但你总是叫这保证了域非空的初始化方法.在这种情况下,您将面临一个权衡:
null!),然后可以使用该字段而不进行空值检查.请注意,通过使用!抑制运算符,您将承担一些风险.想象一下,您实际上并没有按照您的想法一致地初始化所有字段.然后使用null!初始化字段掩盖了a null正在滑入的事实.一些毫无疑问的代码可以接收a null并因此失败.
更一般地说,你可能有一些领域知识:"如果我检查某个方法,那么我知道某些值不为空":
if (CheckEverythingIsReady())
{
// you know that `field` is non-null, but the compiler doesn't. The suppression can help
UseNonNullValueFromField(this.field!);
}
Run Code Online (Sandbox Code Playgroud)
同样,您必须对代码的不变性有信心("我知道更好").