程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C# 3.0語言詳解之基本的語言增強(3)

C# 3.0語言詳解之基本的語言增強(3)

編輯:關於C語言

2、集合初始 化器

我們知道,在C# 1.x和C# 2.0中,可以通過一個包含在花括號之間 的值列表來初始化一個剛剛聲明的數組,如:

int[] intArray = new int[] { 1, 2, 3};

然而,對於和數組有著類似功能的其他 集合(如List)就不能享受這種方便的語法了,只能在聲明完集合對象後將值一 個一個地添加到集合中。而C# 3.0提出了集合初始化器的語言構造,可以用初始 化數組的便捷語法來初始化任何一個實現了ICollection<T>接口的對象。 這裡以C# 2.0中引入的著名的泛型類型List<T>為例:

var intList = new List<int> { 1, 2, 3, 4, 5 };
Console.WriteLine("A list of int:");
foreach(var i in intList)
Console.WriteLine("{0} ", i);

運 行上面這段代碼,可以得到下面的結果:

A list of int:
1
2
3
4
5

前面提到了,這種語法可以 用來初始化任何實現了ICollection<T>接口的對象,這實際上是編譯器的 功勞。編譯器針對這種語法自動生成了循環調用ICollection.Add方法的代碼, 將列表中的值一個一個地添加到正在聲明的集合中。例如:

var intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
intList.Add(4);
intList.Add(5);

另外,也必須是實現了 ICollection<T>的對象才能用這種語法進行初始化,其他具備Add方法但 未實現ICollection<T>的對象不能這樣初始化;同時在聲明中還必須明確 指定類型參數T所代表的實際類型。

匿名類型

在很多情況下,我 們需要一種能夠臨時將一批具有一定關聯的數據存放起來的對象;或者在某些情 況下,我們對僅一個對象的“形狀”(如屬性的名字和類型等)比較 感興趣。例如前面我們提到的Book,當它和其他商品放在一起進行查詢時,我們 可能僅對其名稱和價格感興趣,並且希望將這兩種屬性放在另外一個單獨的臨時 對象中以備今後使用。這時,我們關注的僅僅是這個臨時對象具有Name和Price 的屬性感興趣,至於它究竟是什麼類型就無關緊要了。然而,為了使這樣一個對 象得以存在,我們不得不為這個無關緊要的類型寫上一大堆“樣本代碼 ”,無非就是定義一個如BookAsGood的類,其中無非也就是形如m_name和 m_price的私有域和名為Name與Price的公共可讀寫方法。

而在C# 3.0中 ,我們無須為這些無關緊要的類型浪費時間。通過使用“匿名類型” ,只要在需要一個這樣的對象時使用沒有類型名字的new表達式,並用前面提到 的對象初始化器進行初始化即可。如:

var b1 = new { Name = "The First Sample Book", Price = 88.0f };
var b2 = new { Price = 25.0f, Name = "The Second Sample Book" };
var b3 = new { Name = "The Third Sample Book", Price = 35.00f };
Console.WriteLine(b1.GetType());
Console.WriteLine (b2.GetType());
Console.WriteLine(b3.GetType());

首 先,前面三行聲明並初始化了三個具有匿名類型的對象,它們都將具有公共可讀 寫屬性Name和Price。我們可以看到,匿名類型的屬性連類型都省掉了,完全是 由編譯器根據相應屬性的初始化表達式推斷出來的。這三行稱作“匿名類 型對象初始化器”,編譯器在遇到這樣的語句時,首先會創建一個具有內 部名稱的類型(所謂的“匿名”只是源代碼層面上的匿名,在最終編 譯得到的元數據中還是會有這樣一個名字的),這個類型擁有兩個可讀寫屬性, 同時有兩個私有域用來存放屬性值;然後,和對待對象初始化器一樣,編譯器產 生對象聲明代碼,並依次為每個屬性賦值。

上面代碼的最後三行用來檢 驗匿名類型在運行時的類型,如果嘗試編譯並運行上述代碼,會得到類似下面的 輸出:

lover_P.CSharp3Samples.Ex03.Program+<Projection>f__ 0
lover_P.CSharp3Samples.Ex03.Program+<Projection>f__1
lover_P.CSharp3Samples.Ex03.Program+<Projection>f__0

這表明編譯器的確為匿名類型對象創建了實際的類型,並且該類型在代碼中 是不可訪問的,因為類型的名字不符合C#語言命名規則(其中出現了+、<、 >等非法字符)。

另外,我們還發現一個有趣的現象,由於b1和b2在 初始化的時候其屬性的順序和推斷出來的類型完全一致,它們的運行時類型也是 一樣的;而b2因為屬性出現的順序不同於另外兩個對象,因此具有不同的運行時 類型。通過下面的代碼,我們可以驗證這一事實:

// 正確的賦值 ,b1和b3具有相同的類型
b1 = b3;
// 錯誤的賦值,b1和b2的類型 不同
b1 = b2;

如果嘗試編譯這段代碼,對於第二個賦值我 們會得到一條編譯錯誤:Cannot implicitly convert type ’lover_P.CSharp3Samples.Ex03.Program.<Projection>f__1&rsqu o; to ’lover_P.CSharp3Samples.Ex03.Program.<Projection>f__0&rsqu o;。

這實際上是C# 3.0編譯器固有的特性,在同一個程序集中,編譯器 將為屬性出現順序和類型完全相同的匿名類型對象生成唯一的一個類型。而一旦 屬性的出現順序或類型有所不同,編譯器就會生成不同的類型。另外,在兩個程 序集之中,即使屬性出現的順序和類型一致,編譯器也可能會生成不同的類型, 因此具有匿名類型的對象是不能跨程序集訪問的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved