可空性检查:文字和对象之间的差异,或者:“为什么“if(is null) [..]”适用于对象?但不适用于 int?/long?/..?”

问题描述 投票:0回答:1

我偶然发现了一个有趣的问题,我对此没有任何解释,希望有人能解释一下。

处理可空对象(伪)代码时,如下所示(注意:下面的工作片段):

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.");
    }
}
c# compiler-errors .net-6.0 syntactic-sugar nullability
1个回答
1
投票

可空引用类型和可空值类型完全是从编译器/运行时的角度来看的东西。可空值类型实际上表示为

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)); 

阅读更多:

© www.soinside.com 2019 - 2024. All rights reserved.