Var是C#3.5新增的一個關鍵字,用來代替某些具體的類型,由編譯器自動判斷變量類型,編譯器可以根據變量的初始化值“推斷”變量的類型。
其主要作用有2個:
1.代替具體類型,實現快速編程的隱式類型用法,常見在foreach便歷中,實質是VS編譯器給我們提供的一個語法糖。
2.和new 一起使用,來實現一個匿名類型,用來代替需要預先創建的實體類,靈活高效。
隱式類型用法:
var a=1;//int a=1;
var b="1";//string a="1";
var c=DateTime.Today;//DateTime c=DateTime.Today;
在定義一個具體類型的變量時,可以利用var來代替實際的真正類型,如上,//前面與后面的代碼完全等價,編譯器會自動根據后面的變量值的類型幫我們轉換成最匹配的類型,屬於一個與語法糖。
注意點:
1.無法使用var來定義一個全局變量,只能定義在方法的內部(因為預先不可知,所以預先不可置)
2.不能用來定義函數的簽名,包括返回值,參數類別
3.在定義變量的時候,必須先給值,不能為null,也不能只定義不給值。
4.一旦一個變量被定義成var類型,並確定了指定的類型以后,不能再給這個變量其他類型的值。例: var a="1";a=1;(錯誤:無法將類型“XX”隱式轉換成“YY”)
匿名類型用法:
在實際使用過程中,除了代替具體類型的隱式類型外,更重要的使用方式是定義一個匿名類。
1.1
在開發中,我們有時會像下面的代碼一樣聲明一個匿名類:可以看出,在匿名類的語法中並沒有為其命名,而是直接的一個new { }就完事了。從外部看來,我們根本無法知道這個類是干神馬的,也不知道它有何作用。
var annoyCla1 = new { ID = 10010, Name = "EdisonChou", Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);
經過調試運行,我們發現匿名類完全可以實現具名類的效果:
1.2 深入匿名類背后
既然我們發現匿名類可以完全實現具名類的效果,那么我們可以大膽猜測編譯器肯定在內部幫我們生成了一個類似具名類的class,於是,我們還是借助反編譯工具對其進行探索。通過Reflector反編譯,我們找到了編譯器生成的匿名類如下圖所示:
從上圖可以看出:
(1)匿名類被編譯后會生成一個[泛型類],可以看到上圖中的<>f__AnonymousType0<<ID>j__TPar, <Name>j__TPar, <Age>j__TPar>就是一個泛型類;
(2)匿名類所生成的屬性都是只讀的,可以看出與其對應的字段也是只讀的;
所以,如果我們在程序中為屬性賦值,那么會出現錯誤;
(3)可以看出,匿名類還重寫了基類的三個方法:Equals,GetHashCode和ToString;我們可以看看它為我們所生成的ToString方法是怎么來實現的:
實現的效果如下圖所示:
1.3 匿名類的共享
可以想象一下,如果我們的代碼中定義了很多匿名類,那么是不是編譯器會為每一個匿名類都生成一個泛型類呢?答案是否定的,編譯器考慮得很遠,避免了重復地生成類型。換句話說,定義了多個匿名類的話如果符合一定條件則可以共享一個泛型類。下面,我們就來看看有哪幾種情況:
(1)如果定義的匿名類與之前定義過的一模一樣:屬性類型和順序都一致,那么默認共享前一個泛型類
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today };
var anonymousClass1 = new { ID = 2, Name = "青水白凡", Time = DateTime.Today };
Console.WriteLine($"anonymousClass與anonymousClass1類型:{anonymousClass.GetType() == anonymousClass1.GetType()}");
通過上述代碼中的最后兩行:我們可以判斷其是否是一個類型?答案是:True
(2)如果屬性名稱和順序一致,但屬性類型不同,那么還是共同使用一個泛型類,只是泛型參數改變了而已,所以在運行時會生成不同的類
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today }; var anonymousClass2 = new { ID = "1", Name = "青水白凡", Time = DateTime.Today };
我們剛剛說到雖然共享了同一個泛型類,只是泛型參數改變了而已,所以在運行時會生成不同的類。所以,那么可以猜測到最后兩行代碼所顯示的結果應該是False,他們雖然都使用了一個泛型類,但是在運行時生成了兩個不同的類。
我們剛剛說到雖然共享了同一個泛型類,只是泛型參數改變了而已,所以在運行時會生成不同的類。所以,那么可以猜測到最后兩行代碼所顯示的結果應該是False,他們雖然都使用了一個泛型類,但是在運行時生成了兩個不同的類。
(3)如果數據型名稱和類型相同,但順序不同,那么編譯器會重新創建一個匿名類
var anonymousClass = new { ID = 1, Name = "青水白凡", Time = DateTime.Today }; var anonymousClass3 = new { ID = 1, Time = DateTime.Today, Name = "青水白凡" };
運行判斷結果為:False
通過Reflector,可以發現,編譯器確實重新生成了一個泛型類: