C# 程式語言的未來功能 (轉)

amyz發表於2007-10-31
C# 程式語言的未來功能 (轉)[@more@] 語言的未來功能
Prashant Sridharan
Corporation
年3月

適用於:
 Microsoft® Visual C#(TM)

摘要:Microsoft Corporation 正在開發 C# 語言的下一個主要版本。本文介紹了四種主要的新功能,即泛型、迭代、匿名方法和區域性型別。

目錄

  • #vbconcprogramminglanguagefuturefeaturesanchor1">簡介

簡介

C# 是創新性的新式程式語言,它巧妙地結合了最常用的行業語言和研究語言中的功能。在保持 C# 設計思想不變的同時,Microsoft 在 C# 語言中引入了幾種潛在的新功能,提高了開發人員在語言構造方面的。

Microsoft C#

自 2001 年 2 月 C# 問世以來,很多開發人員已經開始使用 C# 程式語言來構建。而 Microsoft 自身也使用 C# 構建了幾種正式的應用程式,包括 、 屬性和 Tablet PC SDK。由此可見,C# 是一種適用於構造高品質商業軟體的語言。

C# 語言中的許多功能是基於以下四種不同設計目標而建立的:

  • 統一的型別以及簡化值型別和引用型別在 C# 語言中的用法。
  • 透過 註釋、特性、屬性、事件和委託等功能建立基於的設計。
  • 藉助 C# 語言的獨特功能(包括的指標操作、檢查等)建立實用的開發人員控制功能。
  • 建立諸如 foreachusing 語句這樣的實用語言構造,提高開發人員的效率。

在 C# 語言的“ for Yukon”版本中,Microsoft 計劃透過將廣泛的研究語言和行業語言中的各種功能結合在一起建立一種簡潔、實用的語法。這些語言功能包括泛型、迭代程式、匿名方法和區域性型別。

潛在的未來功能

實際上,C# 的未來創新功能主要基於統一的型別系統、基於元件的開發、開發人員控制功能和實用的語言構造。下面總結了 Microsoft 計劃在 C# 語言的下一個主要版本中提供的四種主要的新功能。這些功能的設計尚未完成,Microsoft Corporation 歡迎廣大的開發人員針對這些功能發表評論。

泛型

隨著專案變得越來越複雜,程式設計師日益需要一種方法來更好地重複使用和自定義他們現有的基於元件的軟體。為了實現在其他語言中重複使用高階程式碼,程式設計師通常要使用一種名為“泛型”的功能。C# 將包括一種安全且高效的泛型,它與 C++ 中的模板和 語言中提出的泛型在語法上只是稍有差別,但在實現方式上卻存在很大差別。

生成最新的泛型類

利用目前的 C#,程式設計師可以透過在基本型別的例項中資料來建立有限形式的真正泛型。由於在 C# 中每個物件都是從基本物件型別繼承的,再加上統一 .NET 型別系統的裝箱和取消裝箱功能,程式設計師可以將引用型別和值型別儲存到物件型別的變數中。但是,對於引用型別、值型別與基本物件型別之間的轉換,還有一些缺陷。

為了說明這一點,以下程式碼示例建立了一個簡單的 Stack 型別,其中包含兩個操作“Push”和“Pop”。Stack 類將其資料儲存在物件型別的陣列中,Push 和 Pop 方法使用基本物件型別來接受和返回資料:

public class Stack { private [] items = new object[100]; public void Push(object data) { ... } public object Pop() { ... } }


然後,就可以將自定義型別(例如 Customer 型別)壓入堆疊。但是,如果程式需要檢索資料,則需要將 Pop 方法的結果(基本物件型別)顯式轉換成 Customer 型別。

Stack s = new Stack(); s.Push(new Customer()); Customer c = (Customer) s.Pop();


如果將一個值型別(例如一個整數)傳遞給 Push 方法,執行時會自動將其轉換為引用型別(該過程稱作裝箱),然後將其儲存在內部資料結構中。與此類似,如果程式要從堆疊中檢索一個值型別(例如一個整數),則需要將從 Pop 方法獲取的物件型別顯式轉換成值型別,該過程稱作取消裝箱:

Stack s = new Stack(); s.Push(3); int i = (int) s.Pop();


值型別和引用型別之間的裝箱和取消裝箱操作非常繁重。

而且,在當前的實現中,無法限制堆疊中放置的資料型別。實際上,可以先建立堆疊,然後將 Customer 型別壓入堆疊。然後,可使用同一堆疊並嘗試將資料彈出,接著將其轉換為其他型別,如下例所示:

Stack s = new Stack(); s.Push(new Customer()); Employee e = (Employee) s.Pop();


儘管上一個程式碼示例錯誤地使用了要實現的單個型別 Stack 類,應視為錯誤,但它實際上卻是合法程式碼,對它進行編譯時不會出現問題。但在執行時,該程式會由於無效轉換操作而失敗。

建立和使用泛型

使用 C# 中的泛型可以根據它們所用的型別建立專供使用的高效資料結構。建立這些所謂的引數化型別後,其內部演算法保持不變,但其內部資料的型別可以隨著最終的設定而改變。

為了幫助開發人員節省學習該語言的時間,C# 中泛型的宣告方法與 C++ 中的大致相同。程式設計師可以按通常的方法建立類和結構,並使用尖括號標記(< 和 >)指定型別引數。使用類時,必須用該類的使用者提供的實際型別替換每個引數。

下例將建立一個 Stack 類,在此類宣告後的尖括號中指定並宣告一個名為 ItemType 的型別引數。泛型 Stack 類的例項將接受為其建立的型別並在本地儲存該型別的資料,而不是在建立的型別與基本物件型別之間進行轉換。型別引數 ItemType 充當,直到在例項化過程中指定了型別並將其用作內部項陣列的型別(即 Push 方法的引數型別和 Pop 方法的返回型別):

public class Stack { private ItemType[] items; public void Push(ItemType data) { ... } public ItemType Pop() { ... } }


當程式按照以下示例使用 Stack 類時,您可以指定泛型類使用的實際型別。本例使用例項化語句中的尖括號標記將原始的整數型別指定為引數,指示 Stack 類使用此型別:

Stack stack = new Stack(); stack.Push(3); int x = stack.Pop();


此操作時,程式將建立 Stack 類的新例項,其中的每個 ItemType 都被提供的整數引數替換。實際上,當程式用整數引數建立 Stack 類的新例項時,在 Stack 類內部本地儲存的專案陣列將為整數,而不是物件。程式還消除了與將整數壓入堆疊相關聯的裝箱問題。此外,當程式從堆疊彈出專案時,您無需將其顯式轉換為相應的型別,因為 Stack 類的當前特定例項會將整數本地儲存在其資料結構中。

如果希望程式在 Stack 類中儲存其他型別的專案,則必須建立一個 Stack 類的新例項並將新型別指定為引數。假設有一個簡單的 Customer 型別,希望程式使用 Stack 物件儲存該型別。要實現此操作,只需例項化 Stack 類並將 Customer 物件作為其型別引數,即可輕鬆重複使用程式程式碼:

Stack stack = new Stack(); stack.Push(new Customer()); Customer c = stack.Pop();


當然,如果程式建立了一個將 Customer 型別作為引數的 Stack 類,則只能在該堆疊中儲存 Customer 型別。實際上,C# 中的泛型具有嚴格的型別,這意味著您不能在該堆疊中儲存整數,如以下示例所示:

Stack stack = new Stack(); stack.Push(new Customer()); stack.Push(3) // 編譯時錯誤 Customer c = stack.Pop(); // 不需要型別轉換。


泛型的優點

使用泛型,程式設計師只需編寫、測試和部署一次程式碼,即可對各種不同的資料型別重複使用該程式碼。第一個 Stack 示例具備此功能,第二個 Stack 示例允許程式重複使用對其應用程式效能影響不大的程式碼。對於值型別,第一個 Stack 示例具有較大的效能問題,而第二個 Stack 示例完全消除了這種問題,因為它去除了裝箱和向下的型別轉換。

而且,編譯時還會對泛型進行檢查。當程式使用提供的型別引數例項化泛型類時,此型別引數只能是程式在類定義中指定的型別。例如,如果程式建立了一個 Customer 物件型別的 Stack,就無法將整數壓入堆疊。透過強制執行這種操作,可以生成更可靠的程式碼。

此外,與其他嚴格的型別實現相比,泛型的 C# 實現降低了程式碼的膨脹速度。使用泛型建立具有型別的集合,可以在保持操作效能優勢的同時避免建立每個類的特定變體。例如,程式可以建立一個引數化的 Stack 類,而無需建立用於儲存整數的 IntegerStack、用於儲存字串的 StringStack 以及用於儲存 Customer 型別的 CustomerStack。

這樣可以增加程式碼的可讀性。只需建立一個 Stack 類,程式就可以將與某個堆疊相關聯的所有操作封裝在一個使用方便的類中。然後,在建立 Customer 型別的 Stack 時,儘管其中儲存了 Customer 型別,但顯而易見,程式使用的仍然是堆疊資料結構。

多個型別引數

泛型可以使用任意多個引數型別。上面的 Stack 示例中只使用了一種型別。假設您建立了一個儲存值和鍵的簡單 Dictionary 類。在程式中可以透過宣告兩個引數(放在類定義的尖括號中並用逗號分隔)來定義一個泛型版本的 Dictionary 類:

public class Dictionary { public void Add(KeyType key, ValType val) { ... } public ValType this[KeyType key] { ... } }


使用該 Dictionary 類時,需要在例項化語句的尖括號中提供多個以逗號分隔的引數,併為 Add 和生成器提供正確型別的引數:

Dictionary dict = new Dictionary(); dict.Add(3, new Customer()); Customer c = dict.Get[3];


通常情況下,程式並不僅僅侷限於根據給定的型別引數儲存資料,而是經常需要使用型別引數的成員來執行程式泛型中的語句。

為什麼需要約束

假設在 Dictionary 類的 Add 方法中,您需要使用所提供的鍵的 CompareTo 方法比較專案,例如:

public class Dictionary { public void Add(KeyType key, ValType val) { ... switch(key.CompareTo(x)) { } ... } }


遺憾的是,正如預期那樣,型別引數 KeyType 在編譯時是泛型。如果這樣編寫,編譯器假設對型別引數為 KeyType 的 key 例項只能執行適用於基本物件型別(例如 ToString)的操作。結果,由於 CompareTo 方法未定義,編譯器將顯示編譯錯誤。然而,程式可以將 key 變數轉換為包含 CompareTo 方法的物件,例如 IComparable 介面。在以下示例中,程式將 KeyType 引數型別的例項 key 顯式轉換為程式可以編譯的 IComparable 介面:

public class Dictionary { public void Add(KeyType key, ValType val) { ... switch(((IComparable) key).CompareTo(x)) { } ... } }


然而,如果立即例項化 Dictionary 類而且提供的型別引數沒有實現 IComparable 介面,則程式將遇到執行時錯誤,尤其是 InvalidCastException 異常。

宣告約束

在 C# 中,程式可以為泛型類中宣告的每個型別引數提供可選約束列表。約束表示要將一個型別構造成泛型所必須滿足的要求。可以使用 where 關鍵字宣告約束,該關鍵字後跟“引數-要求”對,其中“引數”必須是泛型中定義的某個引數,“要求”必須是類或介面。

為了滿足在 Dictionary 類中使用 CompareTo 方法的需要,程式可以對 KeyType 型別引數新增約束,要求傳遞給 Dictionary 類作為第一個引數的任何型別都必須實現 IComparable 介面,例如:

public class Dictionary where KeyType : IComparable { public void Add(KeyType key, ValType val) { ... switch(key.CompareTo(x)) { } ... } }


這樣,編譯程式碼時就會檢查程式碼,以確保程式每次使用 Dictionary 類時,作為第一個引數傳遞的型別都實現了 IComparable 介面。此外,程式在 CompareTo 方法之前,再也無需將變數顯式轉換為 IComparable 介面了。

多重約束

對於任何給定的型別引數,程式可以為其指定任意多個介面約束,但最多隻能指定一個類約束。每個新約束都以另一個“引數-要求”對的形式進行宣告,並且給定的泛型的每個約束都用逗號分隔。以下示例中的 Dictionary 類包含兩種引數,KeyType 和 ValType。KeyType 型別引數有兩個介面約束,而 ValType 型別引數有一個類約束:

public class Dictionary where KeyType : IComparable, KeyType : IEnumerable, ValType : Customer { public void Add(KeyType key, ValType val) { ... switch(key.CompareTo(x)) { } ... } }


執行時的泛型

泛型類的編譯方法與常規類的編譯方法幾乎沒有差別。事實上,編譯結果只不過是後設資料和中間語言 (IL)。當然,為了接受程式碼中使用者提供的型別,應對 IL 進行引數化。根據提供的型別引數是值型別還是引用型別,泛型的 IL 的用法會有所不同。

當將值型別作為引數首次構造泛型時,執行時將使用提供的引數替換 IL 中的相應位置來建立一個專用的泛型。針對每個用作引數的唯一值型別,將一次性建立專用的泛型。

例如,假設程式程式碼宣告瞭一個由整數構造的 Stack:

Stack stack;


此時,執行時將生成一個專用的 Stack 類,並用整數替換此類的相應引數。現在,無論程式程式碼何時使用整數 Stack,執行時都將重複使用生成的專用 Stack 類。以下示例將建立整數 Stack 的兩個例項,每個例項均使用由此整數 Stack 的執行時所生成的程式碼來建立:

Stack stackOne = new Stack(); Stack stackTwo = new Stack();


但是,如果在程式程式碼中的其他位置又建立了一個 Stack 類,並使用不同的值型別(例如長整型或使用者定義的結構)作為其引數,則執行時將生成其他形式的泛型,而這時會替換 IL 相應位置中的長整型引數。為使用值型別構造的泛型建立專用類的優點是可以獲得更好的效能。畢竟每個專用的泛型類都是在“本地”包含值型別,因此不必再進行轉換。

泛型與引用型別的工作方式稍有不同。首次使用任何引用型別構造泛型時,執行時用物件引用替換 IL 中的引數來建立專用的泛型。之後,每當使用引用型別作為引數例項化構造的型別時,無論構造的是何種型別,執行時都會重複使用先前建立的專用泛型。

例如,假設有兩個引用型別,Customer 類和 Order 類,並進一步假設您建立了 Customer 型別的 Stack:

Stack customers;


此時,執行時將生成專用 Stack 類,該類並不儲存資料,而是儲存隨後填充的物件引用。假設下一行程式碼建立了一個其他引用型別的 Stack,稱為 Order:

Stack orders = new Stack();


與值型別不同,沒有為 Order 型別建立另一個專用的 Stack 類,而是建立了專用 Stack 類的例項並設定 orders 變數來引用它。對於替換型別引數的每個物件引用,按照 Order 型別的大小分配空間,並將指標設定為引用該記憶體位置。假設您隨後遇到了一行用於建立 Customer 型別的 Stack 的程式碼:

customers = new Stack();


同上一個使用 Order 型別建立的 Stack 類一樣,建立了專用 Stack 類的另一個例項,並將其中包含的指標設定為引用 Customer 型別大小的記憶體區域。由於不同的程式在引用型別的數量上存在著很大差異,因此泛型的 C# 實現透過將引用型別的數量減少到編譯器為引用型別的泛型類建立的專用類數量,大大降低了程式碼的膨脹速度。

此外,當使用型別引數(無論是值型別還是引用型別)例項化泛型 C# 類時,可以在執行時使用反射和實際型別進行查詢,並且可以確定其型別引數。

C# 泛型與其他實現之間的差異

C++ 模板與 C# 泛型存在著顯著的差別。C# 泛型被編譯成 IL,這使得在執行時會智慧地為每個值型別建立相應的專用型別,而為引用型別只會建立一次專用型別;C++ 模板實際上是程式碼擴充套件宏,它為提供給模板的每個型別引數生成一個專用型別。因此,當 C++ 編譯器遇到模板(例如整數 Stack)時,它會將模板程式碼擴充套件為 Stack 類並將整數作為該類本身的型別包含在其中。無論型別引數是值型別還是引用型別,如果不專門設計連結器來降低程式碼膨脹速度,C++ 編譯器每次都會建立一個專用類,從而導致比使用 C# 泛型更顯著的程式碼膨脹速度。

而且,C++ 模板不能定義約束。C++ 模板只能透過使用一個成員(可能屬於也可能不屬於型別引數),隱式定義約束。如果最終傳遞給泛型類的型別引數中存在該成員,程式將正常執行。否則,程式將失敗,並可能返回隱藏的錯誤資訊。由於 C# 泛型可以宣告約束,並且具有嚴格的型別,因此不存在這些潛在的錯誤。

現在,Sun Microsystems® 已經在新版本的 Java 語言(程式碼名稱為“Tiger”)中新增了其他的泛型。Sun 選擇的實現不需要修改 Java 虛擬機器。因此,Sun 面臨著如何在未修改的虛擬機器上實現泛型的問題。

提出的 Java 實現使用與 C++ 中的模板和 C# 中的泛型類似的語法,包括型別引數和約束。然而,由於它處理值型別與處理引用型別的方式不一樣,因此未修改的 Java 虛擬機器不支援值型別的泛型。因此,Java 中的泛型無法得到有效的執行。事實上,Java 編譯器會在需要返回資料時,從指定的約束(如果宣告瞭)或基本物件型別(如果未宣告約束)插入自動向下的型別轉換。此外,Java 編譯器將在執行時生成一個專用型別,然後使用它例項化任何構造型別。最後,由於 Java 虛擬機器本身不支援泛型,因此無法在執行時確定泛型例項的型別引數,而且反射的其他用途也會受到嚴重限制。

其他語言中的泛型支援

Microsoft 的目標是在 Visual J#(TM)、Visual C++ 和 中支援使用和建立泛型。儘管不同語言實現此功能的時間有早有晚,但 Microsoft 的所有其他三種語言都將包含對泛型的支援。同時,C# 小組正努力在泛型的基礎執行時中加入相應的功能,為實現多語言支援奠定基礎。Microsoft 與第三方語言合作伙伴緊密協作,以確保在基於 .NET 的語言中建立和使用泛型。

迭代程式

迭代程式是基於研究語言中的類似功能(例如 CLU、Sather 和 Icon)而構造的語言。簡單說來,透過迭代程式,型別可輕鬆地宣告 foreach 語句對其元素進行迭代的方式。

為什麼需要迭代程式

現在,如果類需要使用 foreach 迴圈結構支援迭代操作,則它們必須實現“列舉器”。例如,編譯器將左側的 foreach 迴圈結構擴充套件為右側的 while 迴圈結構:

List list = ...;

foreach(object obj in list) { DoSomething(obj); }


Enumerator e = list.GetEnumerator();

while(e.MoveNext()) { object obj = e.Current; DoSomething(obj);


值得注意的是,為了使 foreach 迴圈能夠正常執行,List 資料結構(所迭代的例項)必須支援 GetEnumerator 函式。建立 List 資料結構後,必須實現 GetEnumerator 函式,以返回 ListEnumerator 物件:

public class List { internal object[] elements; internal int count; public ListEnumerator GetEnumerator() { return new ListEnumerator(this); } }


所建立的 ListEnumerator 物件不僅必須實現 Current 屬性和 MoveNext 方法,而且還必須維護其內部狀態,以便程式在每次執行該迴圈時都可以移到下一項。此內部狀態機對於 List 資料結構而言比較簡單,但對於需要遞迴迴圈的資料結構(例如二叉樹)來說,該狀態機將相當複雜。

由於實現此列舉器模式需要開發人員投入大量的精力並編寫大量程式碼,因此 C# 包含一種新的結構,使得類可以輕鬆地指示 foreach 迴圈對其內容進行迭代的方式。

定義迭代程式

由於迭代程式是 foreach 迴圈結構的邏輯對應物,因此其定義方式類似於函式:使用 foreach 關鍵字並在後面帶有一對圓括號。在以下示例中,程式將為 List 型別宣告一個迭代程式。迭代程式的返回型別由使用者決定,但是由於 List 類內部儲存的是物件型別,因此以下迭代程式示例的返回型別為物件:

public class List { internal object[] elements; internal int count; public object foreach() { } }


值得注意的是,實現列舉器模式後,程式需要維護內部狀態機以便跟蹤程式在資料結構中的位置。迭代程式具有內建狀態機。使用新的 yield 關鍵字,程式可以將值返回到呼叫該迭代程式的 foreach 語句。當 foreach 語句下次迴圈並再次呼叫迭代程式時,此迭代程式將在上一個 yield 語句停止的位置開始執行。在以下示例中,程式將生成三個字串型別:

public class List { internal object[] elements; internal int count; public string foreach() { yield "microsoft"; yield "corporation"; yield "developer division"; } }


在以下示例中,呼叫此迭代程式的 foreach 迴圈將執行三次,每次都會按照前三個 yield 語句指定的順序接收字串:

List list = new List(); foreach(string s in list) { Console.WriteLine(s); }


如果要讓程式實現迭代程式以遍歷列表中的元素,則需要使用 foreach 迴圈修改此迭代程式使其遍歷元素陣列,並在每次迭代中產生陣列中的每個專案:

public class List { internal object[] elements; internal int count; public object foreach() { foreach(object o in elements) { yield o; } } }


迭代程式的工作原理

迭代程式代表所在的程式處理實現列舉器模式的日常操作。C# 編譯器將您在迭代程式中編寫的程式碼轉換成使用列舉器模式的相應類和程式碼,而無需建立類和建立狀態機。透過這種方式,迭代程式顯著提高了開發人員的工作效率。

匿名方法

匿名方法是另一種實用的語言結構,它使程式設計師能夠建立可裝箱在委託中、並且可在以後執行的程式碼塊。它們基於稱作 λ 函式的語言概念,並且類似於 Lisp 和 中的對應語言概念。

建立委託程式碼

委託是引用方法的物件。呼叫委託時,將呼叫它所引用的方法。以下示例舉例說明了一個簡單的窗體,其中包含列表框、文字框和按鈕三個。初始化按鈕時,程式將指示其 Click 委託引用該物件中其他位置儲存的 AddClick 方法。在 AddClick 方法中,文字框的值儲存在列表框中。由於 AddClick 方法被新增到按鈕例項的 Click 委託中,因此每次單擊該按鈕時都將呼叫此方法。

public class MyForm { ListBox listBox; TextBox textBox; Button button; public MyForm() { listBox = new ListBox(...); textBox = new TextBox(...); button = new Button(...); button.Click += new EventHandler(AddClick); } void AddClick(object sender, EventArgs e) { listBox.Items.Add(textBox.Text); } }


使用匿名方法

上一個示例非常直觀。其中建立了一個單獨的函式,並對其進行了委託引用,每當呼叫此委託時,程式都會呼叫該函式。在該函式中,執行了一系列的可執行步驟。使用匿名方法,程式無需為該類建立整個新方法,而可以直接引用委託中包含的可執行步驟。匿名方法的宣告方法是先例項化一個委託,然後在例項化語句之後加上一對錶示執行範圍的花括號,最後加上一個用於終止語句的分號。

在以下示例中,程式修改委託建立語句以直接修改列表框,而不是引用代表程式來修改該列表框的函式。儲存程式碼的目的是為了修改委託建立語句之後的執行範圍中的列表框。

public class MyForm { ListBox listBox; TextBox textBox; Button button; public MyForm() { listBox = new ListBox(...); textBox = new TextBox(...); button = new Button(...); button.Click += new EventHandler(sender, e) { listBox.Items.Add(textBox.Text); }; } }


請注意,“匿名”方法中的程式碼是如何訪問和處理其執行範圍以外宣告的變數的。實際上,匿名方法可以引用由類和引數宣告的變數,也可以引用所在方法宣告的區域性變數。

向匿名方法傳遞引數

有趣的是,“匿名”方法語句包含兩個引數,即 sender 和 e。檢視 Button 類的 Click 委託的定義,您會發現委託引用的任何函式都必須包含兩個引數,第一個引數為物件型別,第二個引數為 EventArgs 型別。在第一個示例中,程式未使用“匿名”方法,而是向 AddClick 方法傳遞了兩個引數,型別分別為物件和 EventArgs

即使以內聯方式編寫此程式碼,委託仍必須接收兩個引數。在“匿名”方法中,必須宣告兩個引數的名稱,這樣關聯的程式碼塊才能使用它們。當觸發按鈕上的 Click 事件時,將呼叫“匿名”方法並將相應的引數傳遞給該方法。

匿名方法的工作原理

遇到“匿名”委託時,C# 編譯器會自動將其執行範圍內的程式碼轉換為唯一命名類中的唯一命名函式。然後將設定儲存程式碼塊的委託,以引用編譯器生成的物件和方法。呼叫委託時,將透過編譯器生成的方法執行“匿名”方法塊。

區域性型別

儘管在單箇中維護型別的所有是物件導向程式設計的好方法,但有時效能約束會使得型別變大。此外,在某些情況下將型別分割成子型別所耗費的開銷是無法讓人接受的。而且,程式設計師經常會建立或使用應用程式來發布原始碼和修改結果程式碼。遺憾的是,當再次釋出原始碼時,所有現有的原始碼修改將被覆蓋。

區域性型別允許您將包含大量原始碼的型別分割成多個不同的原始檔,以便於開發和維護。此外,區域性型別可用於將生成的型別部分與使用者編寫的型別部分分隔開,從而更易於補充或修改工具生成的程式碼。

在以下示例中,兩個 C# 程式碼檔案 File1.cs 和 File2.cs 中都定義了名為 Foo 的類。如果不使用區域性型別,將會出現編譯錯誤,因為這兩個類存在於同一個名稱空間中。使用 partial 關鍵字,可以指示編譯器:別處可能包含此類的其他定義。

File1.cs File2.cs

public partial class Foo

{ public void MyFunction() { // 在此處執行操作 } }


public partial class Foo

{ public void MyOtherFunction() { // 在此處執行操作 } }


編譯時,C# 編譯器將收集區域性型別的所有定義並將它們組合在一起。編譯器生成的結果 IL 顯示了組合而成的單個類,而不是將多個類分別作為單獨的類進行連續顯示。

符合標準

2001 年 12 月,歐洲計算機制造商協會 (ECMA) 將 C# 程式語言批准為一項標準 (ECMA 334)。此後不久,C# 標準便得到國際標準化組織 (ISO) 的跟蹤處理,預計很快就會得到批准。C# 標準的建立是新程式語言發展史中的重要里程碑,它預示著未來有望在各種平臺上編寫多種實現。實際上,我們從其簡短的歷史中可以看到,許多第三方編譯器供應商和研究人員已經將它當作標準來實現並建立了自己的 C# 編譯器版本。

Microsoft 歡迎客戶對在 C# 語言中新增上面提到的功能提供反饋意見,並打算將這些功能提交給正在進行的語言標準化程式。

可用性

下面介紹的功能將在 C# 編譯器的未來版本中實現。2003 年年初,Visual Studio .NET 的“Everett”版本將包含為完全符合 ECMA 標準而略作修改的 C# 版本。此版本不包含本文介紹的功能。Microsoft 打算在 Visual Studio 的“VS for Yukon”版本中包含這些功能,但具體的釋出日期還未確定。

在接下來的幾個月中,Microsoft 將釋出有關這些功能的詳細資訊,包括所有規範。歡迎廣大程式設計師和語言設計團體就這些功能以及任何其他感興趣的語言功能提出自己的看法和反饋。您可以將電子傳送到 to:sh@microsoft.com,與 C# 語言設計人員取得聯絡。

更多資訊

C# Community Web 站點:

Visual C#(tm) Product Web 站點:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-979919/,如需轉載,請註明出處,否則將追究法律責任。

相關文章