来自’??’的C#类型推断(“var”)赋值

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

我读过很多关于空合并??运算符的so问题,但它们似乎都没有解决以下具体问题,即既不涉及空性(此处)、运算符优先级(此处和此处),也不涉及隐式转换(此处、此处、此处和此处)。我还阅读了.NET文档(这里有更多),并尝试阅读官方规范,但遗憾的是,这些都没有用。

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

1
2
3
4
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非常明确地相反)的全部要点是,从定义上讲,它不可能接受这样的运行时考虑。

换言之,即使我们采用保守但完全可以防御的规则,"绝不超越任何任务看=操作符",这样我们就不会从??的右侧得到任何有用的信息,那么仅从左侧来看,总的结果必须"与"Random兼容。也就是说,结果必须是Random或更具体(派生)的类型;它不能更通用。因此,根据定义,对于这个编译时使用var的情况,Random不应该是推断类型吗?

据我所知,用运行时的考虑来破坏var很快就破坏了它的目的。这正是dynamic的目的吗?所以我想问题是:

  • 对于我对C静态(即编译时)类型哲学的理解,空合并运算符是唯一和/或罕见的例外吗?
  • 如果是的话,那么这个设计与这里看起来正在发生的事情之间的好处或折衷是什么,也就是故意将不确定性引入静态类型推理系统,而这个系统以前没有表现出来?在不破坏静态类型的纯度的情况下,是否可以实现dynamic
  • 通过向开发人员提供可操作的反馈,强类型化不是实现编译时设计严格性的主要要点之一吗?为什么var不能保持严格的保守主义政策——总是推断出可以静态推断的最具体的类型——同时,空合并运算符正在根据未来的信息做它想做的任何事情?


这不是运行时的考虑。

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

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


使用var时,类型在编译时计算出来。因此,当你写下:

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

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

一个更好的例子是:

1
2
3
4
5
6
public interface IA { void Do(); }
public class A : IA { ... }
public class B : IA { ... }

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

something的类型应该是什么:IAAB