新手概念 · 类型

C# 里 var 与显式类型

最常见的误解:var 不是动态类型。变量依然有唯一的类型,由编译器从等号右边挑出来——只是你没亲笔写下它。

var 到底做了什么

类型来自右边,在编译期决定。Visual Studio 里这个程序会打印类型——而且从此再也不变:

var price = 9.99;        // double —— 因为 9.99 是 double 字面量
var count = 42;          // int    —— 因为 42 是 int 字面量
var name = "Ada";        // string

Console.WriteLine(price.GetType());   // System.Double
Console.WriteLine(count.GetType());   // System.Int32
Console.WriteLine(name.GetType());    // System.String

(.GetType() 反射不在浏览器引擎的教学子集里——下面的论断用能在引擎里跑的检查来验证。)

引擎严格的类型检查能在现场证明同一件事——var 变量的行为和它的推断类型一模一样:

var x = 9.99;   // 从这一行起 x 就是 double
int y = x;      // CS0266: 和你写的 'double x = 9.99;' 一模一样

如果 var 是动态的(像 JavaScript),这个赋值早就编译过了。它没有——因为 x 是货真价实的 double,只是被推断出来而已。

第一天就该知道的两个字面量陷阱

var a = 7 / 2.0;    // double: 3.5
var b = 7 / 2;      // int: 3 —— 整数除法,小数没了!

Console.WriteLine(a);
Console.WriteLine(b);

var 忠实地继承表达式产出的东西——包括整数除法的意外(完整故事:为什么 7 / 2 是 3)。

var 的高光时刻

当类型在同一行里已经一目了然时用 var——那它就是纯粹的降噪:

var names = new List<string>();      // 显然是 List<string>
var dog   = new Dog("Rex", 3);         // 显然是 Dog
var total = price * quantity;          // 类型简单时也行

泛型容器是最能感受它的地方——对比:

Dictionary<string, List<int>> scores = new Dictionary<string, List<int>>();  // 写了两遍
var scores2 = new Dictionary<string, List<int>>();                          // 只写一遍
var scores = new Dictionary>();
scores["Ada"] = new List { 90, 85 };

Console.WriteLine($"Ada has {scores["Ada"].Count} scores");

显式类型什么时候赢

当类型是读者无法从别处得知的信息时,写出来:

var label = "count: ";
int n = 5;
Console.WriteLine(label + n);   // 没问题:string + int 拼接

var wrong = n = label;          // 故意写的胡话:把 string 塞进 int 槽

var 必须遵守的规矩

团队惯例,压缩成一张表

场景用为什么
同一行有 newvar类型已经在右边写过了
数值声明显式int 还是 double 是承重信息
方法调用的结果显式(或好名字)读者不该被迫去查
LINQ / 复杂泛型var完整类型名比逻辑本身还长

大多数风格指南(包括微软自己的)落在同一句话:右边能让类型一目了然时用 var,否则写出来。两个老手吵起来,吵的几乎全是"什么算一目了然"。