我偶然发现了一个有趣的问题,我对此没有任何解释,希望有人能解释一下。
处理可空对象(伪)代码时,如下所示(注意:下面的工作片段):
object? obj = GetNullableObject();
if(obj is null) {
return;
}
FunctionRequiringNonNullableObj(obj); // No compile error, object is known to be not null
但是,做同样的事情,例如 long?不:
long? literal = GetNullableLong();
if(literal is null) {
return;
}
FunctionRequiringNonNullableLong(literal); // Compiler error -> Cannot convert long? to long
不知何故,编译器似乎忽略了文字不能再为空的事实。 我假设我遗漏了与性能优化魔术(或相关)相关的东西。
实现了两个版本(对象?和长?)以重现问题。 我的期望是,在这两种情况下,编译器都知道变量不再为空。
using System;
public class Program
{
public static void Main()
{
TestWithObject();
TestWithLiteral();
}
private static void TestWithObject() {
object? obj = ReturnOptionalObject();
if(obj is null) {
Console.WriteLine("Object is null. Returning.");
return;
}
FunctionUsingObject(obj);
}
private static void TestWithLiteral() {
long? literal = ReturnsOptionalLiteral();
if(literal is null) {
Console.WriteLine("Literal is null. Returning.");
return;
}
// Does not work, compiler error
// FunctionUsingLiteral(literal);
}
private static object? ReturnOptionalObject() {
return new object();
}
private static long? ReturnsOptionalLiteral () {
return 123L;
}
private static void FunctionUsingObject(object obj) {
Console.WriteLine("Can access object.");
}
private static void FunctionUsingLiteral(long literal) {
Console.WriteLine("Can access literal.");
}
}
可空引用类型和可空值类型完全是从编译器/运行时的角度来看的东西。可空值类型实际上表示为
Nullable<T>
结构,因此您需要访问 Value
属性:
long? literal = GetNullableLong();
if(literal is null) {
return;
}
FunctionRequiringNonNullableLong(literal.Value);
另一方面,可为空的引用类型没有特定的类型来表示它们(只有一些元数据)并且仅用于可为空的静态分析(默认情况下会产生警告,而不是错误)。
两者都将在可空分析流程方面正确运行,例如,如果您尝试在空检查之前访问
literal.Value
,它将产生警告,因为尝试对 obj
做类似的事情。
另请注意:
Console.WriteLine(typeof(int?) == typeof(int)); // False
Console.WriteLine(typeof(int?) == typeof(Nullable<int>)); // True
// error CS8639: The typeof operator cannot be used on a nullable reference type
// Console.WriteLine(typeof(string?) == typeof(string));
阅读更多: