何时对启用了可空引用类型的参数进行空值检查

When to null-check arguments with nullable reference types enabled

给定一个使用 C# 8.0 的可空引用类型功能的程序中的函数,我是否仍应对参数执行空值检查?

void Foo(string s, object o)
{
    if (s == null) throw new ArgumentNullException(nameof(s)); // Do I need these?
    if (o == null) throw new ArgumentNullException(nameof(o));
    ...
}

None 的代码是 public API 的一部分,所以我怀疑这些检查可能是多余的。这两个参数未标记为可空,因此如果任何调用代码可能传入空值,编译器应发出警告。

Given a function in a program using C# 8.0's nullable reference types feature, should I still be performing null checks on the arguments?

这取决于您对通过 API 的所有路径的确定程度。考虑这段代码:

public void Foo(string x)
{
    FooImpl(x);
}

private void FooImpl(string x)
{
    ...
}

此处 FooImpl 不是 public API 的一部分,但如果 Foo 未验证 ,仍会收到空引用它的 参数。 (实际上,它可能依赖于 Foo 来执行参数验证。)

检查 FooImpl 当然不是 冗余 因为它在执行时执行检查编译器 不能 绝对在编译时确定。可空引用类型提高了一般安全性,更重要的是提高了代码的 表现力 ,但它们与 CLR 提供的类型安全性不同(阻止您处理 string 引用作为 Type 引用,例如)。编译器可以通过多种方式 "wrong" 判断特定表达式在执行时是否为 null,并且无论如何都可以用 ! 覆盖编译器。

更广泛地说:如果您的检查在之前 C# 8 不是多余的,那么它们在之后 C# 8 也不是多余的,因为可空引用类型功能不会更改为代码生成的 IL,除了属性方面。

因此,如果您的 public API 正在执行所有适当的参数检查(上例中的 Foo),那么代码中的检查就已经是多余的了。你对此有多大信心?如果您绝对有信心并且错误的影响很小,那么当然 - 摆脱验证。 C# 8 功能可能会帮助您获得信心,但您仍然需要小心不要 自信 - 毕竟 - 上面的代码不会给出任何警告。

就我个人而言,在为 C# 8 更新 Noda Time 时,我不会删除任何参数验证。