强类型的语言如Java,C#等使用变量前必须声明变量的类型。但C# 3.0中,可以使用新增的关键字var 来代替声明中的类型,而由编译器根据初始化表达式来推断出变量的类型。例如:
var i = 5; // int
var s = "Hello"; // string
var a = new int[] { 1, 2, 3, 4, 5 }; // int[]
var sa = new [] { "Hello", "World" }; // string[]在这些代码中使用了隐式类型的声明,可以通过变量的GetType()方法来验证变量的类型:
Type of variable <i>: System.Int32
Type of variable <d>: System.Double
Type of variable <s>: System.String
Type of variable <a>: System.String[]
这表明,编译器已经正确地推断了每个变量的类型,并将其嵌入到了程序集的元数据中。
此外作用域为一个块的数组也可以有隐式类型的声明。在上面例子的sa 数组声明中,在运算符new和表示数组声明的一对方括号之间省略了类型名字,但这在C# 3.0中仍然是符合语法规则的。编译器会通过成员列表中的值的类型来推断数组的类型。
使用隐藏类型的变量有两个限制:
- 具有隐式类型的声明只能作用在局部变量上,
- 这种声明必须有初始化器(即等号和后面的表达式)。
如果我们企图在一个类中声明一个具有隐式类型的域,就会出现一个编译错误:Invalid token 'var' in class, struct, or interface member declaration;而如果声明中没有出现初始化器,则会导致另外一个编译错误:'=' expected。
具有隐式类型的数组还有必须遵从这样一个规则,即成员列表中的所有值必须是兼容的。也就是说,成员列表中必须存在这样一个值,使得其他值可以隐式地转换为该值的类型。因此,下面的声明是不符合语法规则的:
var aa = new [] { 1, "Hello", 2.0, "World" };如果试图编译上面的代码,会得到一个编译错误:No array type can be inferred from the initializers。这是因为编译器无法根据成员列表中的值来推断数组的类型。
可以在for语句的for-initializer和using语句的resource-acquisition使用具有隐式类型的局部变量声明。同样,foreach语句中的迭代变量也可以被声明为具有隐式类型的局部变量,在这种情况下,迭代变量的类型通过待遍历的集合的元素类型来推断。
int[] numbers = {1, 3, 5, 7, 9};foreach(var n in numbers) Console.WriteLine(n);在上面的例子中n的类型被推断为int——numbers的元素类型。
出于向下兼容的考虑,如果当前作用域中有一个名为var的类时,这个声明使用的是该类;编译器会针对这种模糊的语义给出一个警告。不过由于var违反了类型名字首字母必须大写这条约定,这种情况出现的机会不大。
实际上,尽管具有隐式类型的声明使得传统声明的编写方法更加便利,然而引入这种声明方式的真正目的并不在于此,而是为了使局部变量和数组能够访问这样一个新的语言构造:匿名类型。
>>>
Csharp 3.0 匿名类型