程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#程序設計語言Version2.0簡介

C#程序設計語言Version2.0簡介

編輯:關於C#
 

C# 引入了很多語言擴展,最重要的就是泛型(Generics)、匿名方法(Anonymous Methods)、迭代器(Iterators)和不完全類型(Partial Types)。
• 泛型允許類、結構、接口、委托和方法通過它們所存貯和操作的數據的類型來參數化。泛型是很有用的,因為它提供了更為強大的編譯期間類型檢查,需要更少的數據類型之間的顯式轉換,並且減少了對裝箱操作的需要和運行時的類型檢查。
• 匿名方法允許在需要委托值時能夠以“內聯(in-line)”的方式書寫代碼塊。匿名方法與Lisp語言中的拉姆達函數(lambda functions)類似。
• 迭代器是能夠增量地計算和產生一系列值得方法。迭代器使得一個類能夠很容易地解釋foreach語句將如何迭代他的每一個元素。
• 不完全類型允許類、結構和接口被分成多個小塊兒並存貯在不同的源文件中使其容易開發和維護。另外,不完全類型可以分離機器產生的代碼和用戶書寫的部分,這使得用工具來加強產生的代碼變得容易。

這一章首先對這些新特性做一個簡介。簡介之後有四章,提供了這些特性的完整的技術規范。
C# 中的語言擴展的設計可以保證和現有代碼的高度的兼容性。例如,盡管C#2.0在特定的環境中對單詞where、yield和partial賦予了特殊的意義,這些單詞還是可以被用作標識符。確實,C# 2.0沒有增加一個會和現有代碼中的標識符沖突的關鍵字。

19.1 泛型
泛型允許類、結構、接口、委托和方法通過它們所存貯和操作的數據的類型來參數化。C#泛型對使用Eiffel或Ada語言泛型的用戶和使用C++模板的用戶來說相當親切,盡管它們也許無法忍受後者的復雜性。

19.1.1 為什麼泛型?
沒有泛型,一些通用的數據結構只能使用object類型來存貯各種類型的數據。例如,下面這個簡單的Stack類將它的數據存放在一個object數組中,而它的兩個方法,Push和Pop,分別使用object來接受和返回數據:
public class Stack
{
object[] items;
int count;
public void Push(object item) {...}
public object Pop() {...}
}
盡管使用object類型使得Stack類非常靈活,但它也不是沒有缺點。例如,可以向堆棧中壓入任何類型的值,譬如一個Customer實例。然而,重新取回一個值得時候,必須將Pop方法返回的值顯式地轉換為合適的類型,書寫這些轉換變更要提防運行時類型檢查錯誤是很乏味的:
Stack stack = new Stack();
stack.Push(new Customer());
Customer c = (Customer)stack.Pop();
如果一個值類型的值,如int,傳遞給了Push方法,它會自動裝箱。而當待會兒取回這個int值時,必須顯式的類型轉換進行拆箱:
Stack stack = new Stack();
stack.Push(3);
int i = (int)stack.Pop();
這種裝箱和拆箱操作增加了執行的負擔,因為它帶來了動態內存分配和運行時類型檢查。
Stack類的另外一個問題是無法強制堆棧中的數據的種類。確實,一個Customer實例可以被壓入棧中,而在取回它的時候會意外地轉換成一個錯誤的類型:
Stack stack = new Stack();
stack.Push(new Customer());
string s = (string)stack.Pop();
盡管上面的代碼是Stack類的一種不正確的用法,但這段代碼從技術上來說是正確的,並且不會發生編譯期間錯誤。為題知道這段代碼運行的時候才會出現,這時會拋出一個InvalidCastException異常。
Stack類無疑會從具有限定其元素類型的能力中獲益。使用泛型,這將成為可能。

19.1.2 建立和使用泛型
泛型提供了一個技巧來建立帶有類型參數(type parameters)的類型。下面的例子聲明了一個帶有類型參數T的泛型Stack類。類型參數又類名字後面的定界符“<”和“>”指定。通過某種類型建立的Stack的實例 可以無欲轉換地接受該種類型的數據,這強過於與object相互裝換。類型參數T扮演一個占位符的角色,直到使用時指定了一個實際的類型。注意T相當於內部數組的數據類型、Push方法接受的參數類型和Pop方法的返回值類型:
public class Stack
{
T[] items;
int count;
public void Push(T item) {...}
public T Pop() {...}
}
使用泛型類Stack時,需要指定實際的類型來替代T。下面的例子中,指定int作為參數類型T:
Stack stack = new Stack();
stack.Push(3);
int x = stack.Pop();
Stack類型稱為已構造類型(constructed type)。在Stack類型中出現的所有T被替換為類型參數int。當一個Stack的實例被創建時,items數組的本地存貯是int[]而不是object[],這提供了一個實質的存貯,效率要高過非泛型的Stack。同樣,Stack中的Push和Pop方法只操作int值,如果向堆棧中壓入其他類型的值將會得到編譯期間的錯誤,而且取回一個值時不必將它顯示轉換為原類型。
泛型可以提供強類型,這意味著例如向一個Customer對象的堆棧上壓入一個int將會產生錯誤。這是因為Stack只能操作int值,而Stack也只能操作Customer對象。下面例子中的最後兩行會導致編譯器報錯:
Stack stack = new Stack();
stack.Push(new Customer());
Customer c = stack.Pop();
stack.Push(3); // 類型不匹配錯誤
int x = stack.Pop(); // 類型不匹配錯誤
泛型類型的聲明允許任意數目的類型參數。上面的Stack例子只有一個類型參數,但一個泛型的Dictionary類可能有兩個類型參數,一個是鍵的類型另一個是值的類型:
public class Dictionary
{
public void Add(K key, V value) {...}
public V this[K key] {...}
}
使用Dictionary時,需要提供兩個類型參數:
Dictionary dict = new Dictionary();
dict.Add("Peter", new Customer());
Customer c = dict["Peter">;

19.1.3 泛型類型實例化
和非泛型類型類似,編譯過的泛型類型也由中間語言(IL, Intermediate Language)指令和元數據表示。泛型類型的IL表示當然已由類型參數進行了編碼。
當程序第一次建立一個已構造的泛型類型的實例時,如Stack,.NET公共語言運行時中的即時編譯器(JIT, just-in-time)將泛型IL和元數據轉換為本地代碼,並在進程中用實際類型代替類型參數。後面的對這個以構造的泛型類型的引用使用相同的本地代碼。從泛型類型建立一個特定的構造類型的過程稱為泛型類型實例化(generic type instantiation)。  

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