我一直在具有可空引用类型的项目中自由使用is运算符:

    // Works just fine
    public CheckClass Foo(CheckClass? arg)
    {
        return arg is CheckClass
            ? arg
            : new();
    }

但是,这会引发编译时错误:

    // Cannot convert 'int?' to 'int'
    public int Bar(int? arg)
    {
        return arg is int
            ? arg
            : 0;
    }

通过使用arg上的.Value属性,很容易修复.据我所知,可空引用类型是一种"软"编译时验证,而Nullable<T>是一种"硬"泛型类.

尽管如此,这还是有点令人恼火,而且似乎很奇怪,因为Nullable<T>在很多情况下都得到了优惠待遇.首先,is表达式完全能够判断值的存在,并且如果给它一个名称,它可以生成一个等价类型的不可空对象.

    // Noooo problem
    public int Bar(int? arg)
    {
        return arg is int val
            ? val
            : 0;
    }

这种行为是明确 Select 的,还是疏忽的?如果是前者,背后的理由可能是什么?

推荐答案

这种行为是明确 Select 的,还是疏忽的?如果是前者,背后的理由可能是什么?

基本上是肯定的,这是明确 Select 的.设计团队决定不将nullable reference types(在.NET 6中引入)表示为单独的类型,就像对nullable value types(在.NET Framework2.0中引入)对Nullable<T>所做的那样.所以从编译器的Angular 来看,如果可空引用类型基本上是一堆在编译时分析的元信息,而在这种情况下可空的值类型需要类型转换.

这导致了观察到的行为具有更简约的再现:

int? tempV = null;
object? tempO = null;

// int v = tempV; // Compilation error: Cannot implicitly convert type 'int?' to 'int'
object o = tempO; // warning, depends on the compiler settings

这显然是不理想的,并导致了其他几个问题--比如unconstrained generic handling with nullable types.

首先,is表达式完全能够判断值的存在,并且可以生成等价类型的不可为空的对象(如果给它一个名称).

是的,因为编译器将其识别为基本上为空的判断,并将transforms it识别为类似于:

internal static int Bar(Nullable<int> arg)
{
    if (arg.HasValue)
    {
        return arg.GetValueOrDefault();
    }
    return 0;
}

有关更多信息,请参见-Type testing with pattern matchingPattern matching文档.

备注:

Csharp相关问答推荐

如何将两个查询结果组合在C#ASP.NET MHC控制器中

PredicateBuilder不是循环工作,而是手动工作

如果属性名为xyz,我需要使用System.Text.Json修改字符串类型的值""<>

dotnet集合中内部数组的局部变量副本的用途是什么?'

如何分配对象后的class的属性?

如何在没有额外副本的情况下将存储在IntPtr下的原始图像数据写入WinUI3中的Image控件?

为什么我的表单在绑定到对象时提交空值?

无法通过绑定禁用条目

ASP.NET配置kestrel以使用Windows证书存储中的HTTPS

C#Null判断处理失败

等待一个等待函数

单元测试类型为HttpClient with Microsoft.Extensions.Http.Resilience

是否可以在Entity Framework Core中使用只读 struct 作为拥有实体?

如何在ASP.NET Core 8中获取键控服务词典

如何正确地在VB中初始化类?

Cmd中的&ping.end()";有时会失败,而";ping";总是有效

当要删除的子模型没有父模型的1:多属性时,如何告诉实体框架设置1:1 FK条目?

SqlException:无法打开数据库.升级到Dotnet 8后-数据库兼容性版本-非EFCore兼容性级别

读取测试项目中的应用程序设置

我应该使用IMhemyCache来存储承载令牌,还是应该为Azure函数中的401个错误实施Polly重试策略?