4

我已经阅读了许多关于空合并??运算符的 SO 问题,但它们似乎都没有解决以下具体问题,既不涉及可空性这里)、运算符优先级这里这里),也不是特别是隐式转换这里这里这里这里)。我还阅读了.NET 文档(更多在这里)并尝试阅读官方规范,但遗憾的是无济于事。


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

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

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

CS0841:在声明之前不能使用局部变量 'y'

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

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

现在归零,我认为var关键字的全部意义(特别反对)是,根据定义dynamic,它不受运行时考虑的影响。

换句话说,即使我们采用“从不超越任何赋值=运算符”的保守但完全可以辩护的规则,这样我们因此无法从 的右侧获得任何有用的信息??,然后仅基于左侧,整体结果必须“兼容” Random。也就是说,结果必须是Random或更具体的(派生的)类型;它不能更普遍。因此,根据定义,不Random应该是推断的类型,因为var?

据我所知,var由于运行时的考虑而破坏它会破坏它的目的。这不正是dynamic为了这个吗?所以我想问题是:

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

2 回答 2

4

这不是运行时考虑。

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

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

于 2017-07-09T02:43:15.470 回答
0

当您使用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:IA或的类型应该是A什么B

于 2017-07-09T02:19:39.450 回答