来自“??”的 C# 类型推断 ("var") 赋值零合并运算符

C# type inference ("var") assignment from '??' null-coalescing operator

我读过许多关于空合并 ?? 运算符的 SO 问题,但其中 none 似乎解决了以下特定问题,该问题既不涉及 可空性 (here), operator precedence (here and here) nor especially implicit conversion (here, here, here and here). I've also read the .NET docs (more here) and tried to read the offical spec, 但遗憾的是都无济于事。


所以开始了。以下两行之间的唯一区别是在第二行中使用 var 进行类型推断,而在第一行中使用显式类型 Random,但是第二行给出了如图所示的错误,而第一行是就好了。

Random x = new Random() ?? (x = new Random());        // ok

var    y = new Random() ?? (y = new Random());        // CS0841
                        //  ^-------- error here

CS0841: Cannot use local variable 'y' before it is declared

第二行究竟是什么让结果不确定?

从我上面引用的 hubub 中,我了解到 ?? 运算符的左侧是 null 的可能性引入了对其实际实例化类型的运行时确定的依赖性右边。嗯,好吧,我猜,……什么意思?也许这个网站上关于 ?? 操作员的大量警报应该是某种可怕的警告......

现在归零,我认为 var 关键字(与 dynamic 完全相反)的全部意义在于它不受运行时考虑的影响,根据定义.

换句话说,即使我们采用"never peering beyond any assignment = operator"的保守但完全可以防御的规则,以至于我们因此从??的右侧得不到任何有用的信息,那么基于仅在左侧,整体结果 必须 为 "compatible with" Random。也就是说,结果必须是 Random 或更具体(派生)的类型;它不能更笼统。因此,根据定义,对于 var?

的编译时使用,Random 不应该是推断类型

据我所知,出于运行时的考虑而破坏 var 显然会违背其目的。这不正是 dynamic 的用途吗?所以我想问题是:

当您使用 var 时,类型是在编译时确定的。因此,当你这样写的时候:

var    y = new Random() ?? (y = new Random()); 

编译器无法在编译时确定y的类型,因此开始大喊大叫-决定??的左侧是否为空,将在运行时确定。

一个更好的例子是:

public interface IA { void Do(); }
public class A : IA { ... }
public class B : IA { ... }

A a = null;
var something = a ?? new B(); 

something 的类型应该是什么:IAAB

这不是运行时考虑因素。

使用var声明的变量的编译时类型是其初始值设定项的静态类型。 ?? 表达式的静态类型是两个操作数的静态类型的公共类型。但是第二个操作数的静态类型是y的静态类型,这是未知的。因此整个初始化器的静态类型未知,推导失败。

确实存在初始化一致的类型,但无法使用 C# 推理规则找到它们。