给出使用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));
...
}
这些代码都不是公共API的一部分,因此我怀疑这些检查可能是多余的。这两个参数未标记为可为空,因此,如果有任何调用代码可能传入null,则编译器应发出警告。
答案 0 :(得分:7)
给出使用C#8.0的可为空的引用类型功能的程序中的函数,我是否仍应对参数执行空值检查?
这取决于您对通过API的所有路径的确定性。考虑以下代码:
public void Foo(string x)
{
FooImpl(x);
}
private void FooImpl(string x)
{
...
}
此处FooImpl
不是公共API的一部分,但是如果Foo
不验证其参数,仍可以收到空引用。 (实际上,可能依靠Foo
来执行参数验证。)
签入FooImpl
当然不是多余,因为它在执行时执行检查,使编译器不能在编译时绝对确定。可空的引用类型提高了常规安全性,更重要的是提高了代码的 expressiveness ,但它们与CLR提供的类型安全性不同(停止将string
引用视为Type
引用)。对于特定表达式在执行时是否为null的看法,编译器有多种“错误”的看法,而且无论如何,编译器都可以用!
覆盖。
更广泛的说:如果您的检查在C#8之前不是多余的,则它们在C#8之后的也不是多余的,因为可空引用类型功能不会改变为代码生成的IL,而不是根据属性生成的。
因此,如果您的公共API正在执行所有适当的参数检查(上例中为Foo
),则代码中的检查已经是多余的。您对此有多自信?如果您绝对有信心,并且犯错的影响很小,那么可以确定-摆脱验证。 C#8功能可以帮助您增强对此的信心,但是您仍然需要小心,不要让太充满信心-毕竟-上面的代码不会给出警告。
就C#8更新Noda Time而言,我个人并没有删除任何参数验证。