类型推理

  本书前面介绍过C#是一种强类型化的语言,这表示每个变量都有固定的类型,只能用于接受该类型的代码中。在前面的所有代码示例中,都采用如下两种形式的代码来声明变量:

  1. <type> <varName>;

  或者

  1. <type> <varName> = <value>;

  下面的代码显示了变量<varName>的类型:

  1. int myInt = 5;
  2. Console.WriteLine(myInt);

  将鼠标指针停放在变量标识符上,IDE就会显示该变量的类型。

  C# 3引入了新关键字var,它可以替代前面代码中的type:

  1. var <varName> = <value>;

  在这行代码中,变量<varName>隐式地类型化为<value>的类型。注意,类型的名称并不是var

在下面的代码中:

  1. var myVar = 5;

  myVar是int类型的变量,而不是var类型的变量,IDE也显示了其类型。

  这是非常重要的一点。使用var时,并不是声明了一个没有类型的变量,也不是声明了一个类型可变的变量。否则,C#就不再是强类型化的语言了。实际上,我们所做的只是依赖于编译器来确定变量的类型。

  .NET 4引入的动态类型扩展了C#是强类型化语言的定义,参见本章后面的“动态查找”一节。

  如果编译器不能确定用var声明的变量类型,代码就无法编译。因此,在用var声明变量时,必须同时初始化该变量,因为如果没有初始值,编译器就不能确定变量的类型。因此,下面的代码就无法编译:

  1. var myVar;

  var关键字还可以通过数组初始化器来推断数组的类型:

  1. var myArray = new[] { 4, 5, 2};

  在这行代码中,myArray类型被隐式地设置为int[]。在采用这种方式隐式指定数组的类型时,初始化器中使用的数组元素必须是以下情形中的一种:

  1. 相同的类型
  2. 相同的引用类型或空
  3. 所有元素的类型都可以隐式地转换为一个类型

  如果应用最后一条规则,元素可以转换的类型就称为数组元素的最佳类型。如果这个最佳类型有任何含糊的地方,即所有元素的类型都可以隐式转换为两种或更多的类型,代码就不会编译。我们会接收到错误,错误中指出没有最佳类型:

  1. var myArray = new[] { 4, "not an int", 2 }; // ❌

  还要注意数字值从来都不会解释为可空类型,所以下面的代码无法编译:

  1. var myArray = new[] { 4, null, 2 }; // ❌

  但可以使用标准的数组初始化器,使如下代码编译:

  1. var myArray = new int [] { 4, null, 2 };

  最后一点要说明的是,标识符var并非不能用于类名。这意味着,如果代码在其作用域中(在同一个名称空间或引用的名称空间中)有一个var类,就不能使用var关键字的隐式类型化功能。

  类型推理功能本身并不是很有效,因为在本节前面的代码中,它只会使事情更复杂。使用var会加大判断给定变量的类型的难度。但如本章后面所述,推断类型的概念非常重要,因为它是其他技术的基础。下一个主题是匿名类型,它就以推断类型为基础。