我正在尝试在C#8.0中使用可空引用类型。我已经设置了一个示例代码对其进行测试,但是有些事情使我感到困惑!
据我了解,当我们不将?
加到Type
时,它被视为不可为空。那么,为什么在Main()方法中,编译器没有抱怨我要对照myClass
检查null
?在编译器看来myClass
是不可为空的吗?
#nullable enable
using System;
namespace ConsoleApp4
{
class Program
{
static void Main()
{
var service = new Service();
MyClass myClass = service.GetMyClass();
// I am curious why this line compiles!
if (myClass == null)
{
throw new ArgumentNullException();
}
}
}
public sealed class Service
{
private MyClass? _obj;
public MyClass GetMyClass()
{
if (_obj == null)
{
_obj = new MyClass();
}
return _obj;
}
}
public sealed class MyClass
{
}
}
至此,对于编译器来说,myClass是不可为空的吗?
确实是这样。将鼠标悬停在无效检查上的myClass
上,静态分析的工具提示将告诉您myClass
在此处不为空。
所以,为什么要检查它是否为null?因为你能。它仍然是引用类型。它不会为null的事实未在类型中进行注释。
此外,请注意,它并没有告诉您异常不是可到达的代码。为什么会这样?
嗯,C#8.0可为空的引用不是万无一失的。它们在大多数情况下都足够好。但是,有时会出现一些无法识别的模式。需要注释和允许空值的运算符(!)。您可以使用哪个来告诉编译器何时您更了解。但是,这些让编译器可以说谎:
public MyClass GetMyClass()
{
return _obj!;
}
类似地,根据静态编译器,您可以检查某些内容是否为null。因为您更了解:
public sealed class Service
{
private MyClass? _obj;
public MyClass GetMyClass()
{
return _obj!;
}
}
internal static class Program
{
private static void Main()
{
var service = new Service();
var myClass = service.GetMyClass();
// I am curious why this line compiles!
if (myClass == null)
{
throw new ArgumentNullException();
}
}
}
当然,我不建议您继续对编译器撒谎。但是,如果您从第三方接收参数,建议仍然进行空检查。同样,当使用公共API时,您将无法信任实现。