c# - 什么是空!声明是什么意思?

标签 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;
    }
}
基本上,我尝试深入研究 c# 8 的新功能。其中之一是NullableReferenceTypes .
实际上,已经有很多关于它的文章和信息。例如this article很好。
但是我没有找到关于这个新声明的任何信息null!有人可以给我一个解释吗?
为什么我需要使用这个?
line1有什么区别和 line2 ?

最佳答案

了解什么的关键null!意思是理解!运营商。 您之前可能已经将它用作“非”运算符。但是,由于 C# 8.0 和它的新 "nullable-reference-types"功能,运算符(operator)得到了第二个含义。它可以用于 类型 为了控制可空性,它被称为 "Null Forgiving Operator"

典型用法
假设这个定义:

class Person
{
    // Not every person has a middle name. We express "no middle name" as "null"
    public string? MiddleName;
}
用法是:
void LogPerson(Person person)
{
    Console.WriteLine(person.MiddleName.Length);  // WARNING: may be null
    Console.WriteLine(person.MiddleName!.Length); // No warning
}
此运算符基本上关闭了针对此用法的编译器空值检查。
技术说明
零安全
C# 8.0 试图帮助您管理您的 null -值。而不是允许您分配 null默认情况下,他们对所有内容进行了翻转,现在需要您明确标记您希望能够容纳的所有物品 null值(value)。
这是一个 super 有用的功能,它可以让你避免NullReferenceException s 通过强制您做出决定并执行它。
工作原理
在谈论空安全时,变量可以处于 2 种状态。
  • 可空 - 可以 为空。
  • 不可为空 - 不能为空。

  • Since C# 8.0 all reference types are non-nullable by default. Value types have been non-nullable since C# 2.0!


    “可空性”可以通过 2 个新的(类型级)运算符进行修改:
  • ! = 来自 NullableNon-Nullable
  • ? = 来自 Non-NullableNullable

  • 这些运算符是彼此对应的。
    Compiler 使用您通过这些运算符定义的信息来确保空值安全。
    例子?运算符(operator)使用。
    这个运算符告诉编译器一个变量可以保存一个空值。
  • 可空 string? x;
  • x是引用类型 - 因此默认情况下不可为空。
  • 我们申请 ?运算符 - 这使它可以为空。
  • x = null工作正常。

  • 不可为空 string y;
  • y是引用类型 - 因此默认情况下不可为空。
  • y = null生成警告,因为您将空值分配给不应为空的内容。


  • 很高兴知道:使用 string?System.Nullable<string> 的语法糖!运算符(operator)使用。
    这个操作符告诉编译器一些可能为空的东西是可以安全访问的。 在这种情况下,您表达了“不关心”空安全的意图。
    string x;
    string? y;
    
  • x = y
  • 非法! Warning: "y" may be null
  • 赋值的左边是不可为空的,而右边是可以为空的。
  • 确实如此 不是 工作,因为它在语义上不正确

  • x = y!
  • 合法!
  • y是带有 ? 的引用类型应用了类型修饰符,因此如果没有另外证明,它可以为空。
  • 我们申请 !y其中覆盖 它的可空性设置使其成为 不可为空
  • 赋值的右侧和左侧是不可为空的。这在语义上是正确的。


  • WARNING The ! operator only turns off the compiler-checks at a type-system level - At runtime, the value may still be null.


    慎用!
    你应该尝试 避免 使用 Null-Forgiving-Operator,自 起,使用可能是系统设计缺陷的征兆。它否定了编译器保证的空安全的影响。
    推理
    使用 !运算符(operator)会产生很难找到的错误。 如果您有一个标记为不可为空的属性,您将假定您可以安全地使用它。但是在运行时,你突然遇到了 NullReferenceException抓挠你的头。由于在使用 ! 绕过编译器检查后,值实际上变为空值。 .
    那为什么会存在这个运算符呢?
    存在适合使用的有效用例(在下面详细概述)。但是,在 99% 的情况下,您最好使用替代解决方案。请不要打几十个!在您的代码中,只是为了使警告静音。
  • 在某些(边缘)情况下,编译器无法检测到可空值实际上不可为空。
  • 更轻松的遗留代码库迁移。
  • 在某些情况下,您只是不在乎某些内容是否为空。
  • 使用单元测试时,您可能希望在出现 null 时检查代码的行为。通过。

  • 好吗!?但什么是null!是什么意思?
    它告诉编译器 null不是 nullable值(value)。听起来很奇怪,不是吗?
    y!从上面的例子。 它看起来很奇怪,因为您将运算符应用于 null文字 .但概念是一样的。在这种情况下,null文字与任何其他表达式/类型/值/变量相同。
    null文字类型是默认情况下唯一可以为空的类型!但正如我们所了解的,任何类型的可空性都可以用 ! 覆盖。不可为空。
    类型系统不关心变量的实际/运行时值。只有它的编译时类型以及在您的示例中要分配给 LastName 的变量( null! ) 是 non-nullable ,就类型系统而言这是有效的。
    考虑一下这段(无效的)代码。
    object? null;
    LastName = null!;
    

    关于c# - 什么是空!声明是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54724304/

    相关文章:

    c# - using 和 await using 有什么区别?我如何决定使用哪一个?

    c# - 如何将 C# 8 中的默认返回值标记为仅对类可为空?

    c# - 当 FirstOrDefault 在排序列表中找不到任何内容时,我如何理解?

    c# - 如何打开 Windows 10 ms-settings 特定页面而不访问其他设置

    c# - 可空性分析无法对来自 NameValueCollection 的 null 发出警告。为什么?

    c# - 如何允许 C# 8 中可为 null 的泛型类型作为方法的返回类型?

    c# - 为什么我的局部变量可能为空,即使该方法返回非空?

    c# - 没有任何事件的 Treeview 闪烁

    c# - 转换类型

    c# - 从异步方法返回IAsyncEnumerable