为何is not { }模式匹配可空值类型与引用类型时可空性表现不同?
关于C#中
is not {}模式与可空类型的类型推断问题 先搞懂底层:可空值类型和可空引用类型根本不是一回事
C#里这俩可空是完全不同的实现:
int?这种可空值类型是Nullable<T>结构体,相当于给值类型套了个“有没有值”的标记,非null状态下必然有一个有效的int值。Location?这种可空引用类型只是编译器的静态注解,运行时它还是普通的Location引用,空值就是普通的null引用,没有额外包装。
两种模式的本质差异
1. 类型模式(is not Location loc/is not int id)
你写is not 类型 变量的时候,是在做类型匹配检查:
- 对
int?来说,is not int id相当于“这个可空int不是null,并且能转成int”,所以id直接被推断成非空的int——毕竟只有非null的int?才能匹配int类型。 - 对
Location?来说,is not Location loc是“这个可空引用不是null,并且是Location类型”(本来就是),编译器会直接把loc推断成非空的Location——因为你明确指定了要匹配的类型,编译器就会去掉可空注解。
2. 空模式(is not {})
is not {}就是is not null的简写,它只做null检查,不涉及类型转换:
- 对
int?来说,非null就意味着有有效的int值,编译器可以安全地把id推断成int(自动解包)。 - 对
Location?来说,is not {}只告诉你这个引用不是null,但不会自动修改变量的可空注解——因为可空引用类型的注解是静态分析用的,空模式没说要把它转成非空类型,所以loc的类型还是Location?,只是编译器静态分析时知道它现在不为null(代码里可以安全用,不用加空判断)。
再看Roslyn文档的例子
文档里的int? x = 3; if (x is int v)是类型模式,编译器通过类型匹配自动解包了可空值类型,所以v是int——这和你第一个场景里is not int id的逻辑完全一致,都是类型模式触发的自动转换。而空模式不做类型转换,所以引用类型不会改可空注解。
内容的提问来源于stack exchange,提问作者exSnake
相关产品推荐
相关产品推荐

