隱式類型的局部變量
在C# 1, C# 2中, 其類型系統是靜態的, 顯式和安全的. 在C# 3中, 這一點也幾乎一致. 首先, 類型系統依然是靜態和安全的(忽略顯式的unsafe代碼), 並且多數情況下, 它依然還是顯式的——不過你也可以讓編譯器幫你推斷局部變量的類型.
使用var聲明局部變量
要使用隱式類型, 只需要簡單的將原先聲明的特定類型的局部變量改用var來聲明, 當然會有一些限制, 我們稍候討論, 不過基本上你只需要做類似下面這樣的改變:
1: MyType variableName = someInitialValue;
改為:
1: var variableName = someInitialValue;
這兩行代碼實際上是一樣的(基於編譯後的代碼), someInitialValue的類型都是MyType. 編譯器在編譯時可以根據初始化表達式判斷類型並使得變量也擁有該類型. 其類型可以是任意的.NET類型, 包括泛型, 代理, 和接口. 變量依然還是靜態的, 只是你沒有將類型名寫在你的代碼中而已.
1: var stringVariable = "Hello, world.";
2: stringVariable = 0;
以上的代碼不能編譯通過, 因為stringVariable的類型是System.String, 而我們不能將值0賦給一個字符類型的變量. 在很多動態語言中, 上面的代碼是可以編譯通過的, 它們不會給予變量特定的類型, 相反這是編譯器, IDE或者運行時環境要考慮的. 使用var並不像使用COM或者VB6中的Variant. var聲明的變量類型依然是靜態的; 只不過類型是由編譯器推斷的而已.
在VS2008中, 當你的鼠標停留在var所聲明的變量上的時候, 其智能提示可以告訴你該類型的精確類型, 這與我們聲明顯式類型的時候是一樣的。這也更清晰的表明了var聲明的變量類型是靜態的——編譯器清楚的知道變量類型.
隱式類型的限制
你不能在所有的情況下對每一個變量都使用隱式類型聲明. 只有當在下列情況之一時使用:
其中, 第3點與第4點是很有趣的, 你不能這樣編寫:
1: var starter = delegate() { Console.WriteLine(); }
因為編譯器不知道你將要使用的類型, 然而你可以使用下面的代碼:
1: var starter = (ThreadStart) delegate() { Console.WriteLine(); }
但如果你要這麼做的話最好在開頭空白的地方就使用顯式類型聲明. 同樣的做法也適用於null的情況——你應該將null轉換為適當的類型. 另外我們也可以使用方法調用值或者屬性作為初始化表達式——指向常量或者構造器調用也是沒有問題的. 例如, 可以使用下列的代碼:
1: var args = Environment.CommandLine;
在這個例子中, args將會被初始化為string[]類型.實際上, 將方法調用的返回值賦給一個變量在LINQ to SQL當中幾乎是最常用的一種情景. 另外, 還有一點也是值得注明一下的, 在using, for, foreach的頭一個部分使用var聲明是被允許的, 例如:
1: for (var i = 0; i < 10; i++)
2: using (var x = File.OpenText("test.dat"))
3: foreach (var s in Environment.CommandLine)
上述代碼中的變量將會各自結束於int, StreamReader和string類型. 當然, 僅僅是被允許這麼做並不意味著你就應該要這樣做. 讓我們來看一下支持和反對使用隱式類型聲明的理由.
隱式類型聲明的好與壞
使用隱式類型聲明的主要理由(先排除匿名類型)是它減少了大量的代碼輸入, 同時屏幕上可見的代碼數量也變多了:) 特別是當類型名包含泛型的時候可能會很長, 因為太長你可能會使用一行來聲明變量, 另外一行用於初始化表達式. 另外的一種選擇使用別名, 但那樣的話為了要看到變量的真實類型你可能要經過一道長長的路途(無法在查看變量的時候就知道其真實類型). 相反, 如果使用var, 這一切都迎刃而解, 代碼也更少, 編輯器也可以及時告訴你具體的變量類型.
所有的這些聽起來都不錯, 那麼我們有什麼理由來反對使用隱式類型聲明呢? 可讀性!其幾乎是反對使用隱式類型聲明最重要的一個理由. 對於沒有使用顯式聲明的變量來說, 代碼可能會更難讀一點. 它打破了”我們聲明的是什麼類型, 那麼其就應該始於對應的初始值”的思維, 這使得聲明初始化完全分離了. 至於難讀的程度則去取決於讀者和初始化表達式所包含的代碼. 如果是顯式調用一個構造器, 那麼這可以非常明顯的知道你要創建的是什麼類型. 如果是調用一個方法或者使用一個屬性, 則取決於返回類型是否足夠明顯. 下面整數型的列子顯示了推斷類型比顯式聲明更加困難, 多快你可能區分中每一種類型所對應的真實類型?
1: var a = 2147483647;
2: var b = 2147483648;
3: var c = 4294967295;
4: var d = 4294967296;
5: var e = 9223372036854775807;
6: var f = 9223372036854775808;
答案是int, uint, long, long和ulong. 這些類型完全依賴於表達式的結果.
建議
以下是個人的一些關於使用隱式類型的建議