[ C# 3.0/.NET 3.x 新增特性 ]
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 annoyCla1 = new { ID = 10010, Name = "EdisonChou", Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID, annoyCla1.Name, annoyCla1.Age); Console.WriteLine(annoyCla1.ToString()); // 02.屬性類型和順序與annoyCla1一致,那么共同使用一個匿名類 var annoyCla2 = new { ID = 10086, Name = "WncudChou", Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla1.ID, annoyCla1.Name, annoyCla1.Age); Console.WriteLine("Is The Same Class of 1 and 2:{0}", annoyCla1.GetType() == annoyCla2.GetType());
通過上述代碼中的最后兩行:我們可以判斷其是否是一個類型?答案是:True
(2)如果屬性名稱和順序一致,但屬性類型不同,那么還是共同使用一個泛型類,只是泛型參數改變了而已,所以在運行時會生成不同的類:
var annoyCla3 = new { ID = "EdisonChou", Name = 10010, Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla3.ID, annoyCla3.Name, annoyCla3.Age); Console.WriteLine("Is The Same Class of 2 and 3:{0}", annoyCla3.GetType() == annoyCla2.GetType());
我們剛剛說到雖然共享了同一個泛型類,只是泛型參數改變了而已,所以在運行時會生成不同的類。所以,那么可以猜測到最后兩行代碼所顯示的結果應該是False,他們雖然都使用了一個泛型類,但是在運行時生成了兩個不同的類。
(3)如果數據型名稱和類型相同,但順序不同,那么編譯器會重新創建一個匿名類
var annoyCla4 = new { Name = "EdisonChou", ID = 10010, Age = 25 }; Console.WriteLine("ID:{0}-Name:{1}-Age:{2}", annoyCla4.ID, annoyCla4.Name, annoyCla4.Age); Console.WriteLine("Is The Same Class of 2 and 4:{0}", annoyCla4.GetType() == annoyCla2.GetType());
運行判斷結果為:False
通過Reflector,可以發現,編譯器確實重新生成了一個泛型類:
出處:http://edisonchou.cnblogs.com