为什么仍然可以将 null 分配给不可为 null 的引用类型?

Why is it still possible to assign null to non nullable reference type?

我很困惑。 我认为启用 c# 8 和可为空的引用类型会阻止将 null 分配给非可为空的引用类型,但显然这只是编译时的警告,我知道你可以将其强制为错误并停止构建,但我认为这不仅仅是编译器检查。

看看这个例子 https://dotnetfiddle.net/4eCs5L

如果您 运行,仍然可以将 null 分配给不可为 null 的引用类型,为什么在 运行 时不抛出错误?

使用此引用 https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references

我可以看到指令 #nullable enable: Sets the nullable annotation context and nullable warning context to enabled

如果您仍然希望它抛出错误,请将其添加到您的项目文件中 <WarningsAsErrors>nullable</WarningsAsErrors>

TLDR:向后兼容性

如果可空引用类型是 C# 1 的一部分,那么 null 对非可空类型的赋值会引发编译错误。

C# 的问题是已经有很多没有 Nullable Reference Types 的现有代码。 null 分配的编译器错误会破坏所有现有代码或库。

您可以在 C# 程序管理器的 .NET 博客 Post 中找到完整的解释:https://devblogs.microsoft.com/dotnet/nullable-reference-types-in-csharp/

该功能的目的是为开发人员提供更多工具来捕获最普遍的错误类型,解除对空引用/指针的引用,从而导致应用程序崩溃。

因此,C# 设计团队添加了“可空引用类型”,具有足够的语法,开发人员可以更清楚地声明代码的意图和要求。

新语法可以表达的东西:

  • 允许 NULL 或不允许 NULL 的属性和字段
  • 方法参数可以为NULL,或者应该为NULL
  • 方法 return 可以为 NULL 或不会为 NULL 的值

启用后,编译器将使用这种新语法、属性和其他元数据,在发现不“保证”正确的代码时开始发出警告。换句话说,如果你读到一个 属性 说它可以 return NULL,并尝试将它作为参数值传递给方法说参数不应该为 NULL,你会收到警告。

您可以在项目上使用现有指令,将某些警告作为错误处理,并中断构建,这包括这些新警告。

但是,他们没有添加的是 运行时间检查。如果您说参数值永远不应该为 NULL,并且忽略警告或绕过它(有很多方法可以说“相信我,这是正确的”),那么该方法将 运行 如前所述。没有不可见的 if 语句或 guard 语句来验证参数不为 null。

基本上,您仍然应该添加这样的 if 语句。

与您的看法相反,这正是他们设计此功能的目的。他们没有忘记添加这些 运行 时间检查,他们故意没有添加它们。

例如,如果您通过反射调用方法,编译器不会参与,因为它是 运行time 事情,因此根本不会执行任何检查。如果该方法没有这样的保护语句,它可能稍后会因 NullReferenceException 而崩溃。