Visual C# .NET 2003 語言的改變 (轉)

amyz發表於2007-08-14
Visual C# .NET 2003 語言的改變 (轉)[@more@]Visual 語言的改變
Prashant Sridharan
Corporation
2002年12月30日

適用於:
 Microsoft ® C# 2003

摘要:為了與歐洲製造商協會 (ECMA) 的 C# 規範完全相容,Microsoft Corporation 對 C# 的實現進行了幾處改動。這些改動將在多方面影響現有的程式碼,因此必須檢查他們的程式碼以確保這些程式碼符合 C# 語言必需的和推薦的使用要求。

目錄

  • #vbtchvisualcnet2003languagechangesanchor1">背景

背景

2001 年年底,ECMA 將 C# 程式語言批准為一項標準 (ECMA-334)。為了與 Microsoft 在 C# 和公共語言介面 (CLI) 標準化程式方面的舉措保持一致,Microsoft 遵循 ECMA C# 標準的精神和文字規範對 C# 編譯器進行了幾處小的改動。另外,Microsoft 在遵循 C# 標準規範的同時對 C# 實現作了一些額外的小改動,並更正了 C# 員遇到的一些編譯器問題和錯誤。其中的每處改動都可能導致使用 Visual C# .NET 2002 版編譯器編寫的程式碼在用於 Visual C# .NET 2003 之前必須進行修改。

C# 語言的新功能

Visual C# .NET 2003 版的 C# 語言中新增了兩個新功能。第一,編譯器現在支援 #line hidden 預指令。#line hidden 指令主要用於生成器,它通知編譯器忽略緊跟在 #line hidden 指令後面的所有程式碼行的程式資訊,直到遇到下一個 #line 指令為止(該 #line 指令的除錯程式資訊也一併被忽略),這裡假設它們中間不會立即碰到下一個 #line hidden 預處理指令。在下面的示例中,編譯器生成了 IL 程式碼,其中的 WriteLine 語句不包含除錯資訊。這樣,除錯應用程式的程式設計師將無法檢視“隱藏”的程式碼並檢查其中的內容:

public class Customer { public static void Main() { MyClass c = new MyClass(); c.ExecuteCommand(); #line hidden Console.WriteLine("顯示一些文字"); Console.WriteLine("顯示一些文字"); Console.WriteLine("顯示一些文字"); #line c.Procesmmand(); c.Close(); } }


然而,#line hidden 指令並不隱藏編譯器錯誤。當然,編譯器仍然將程式碼編譯到 IL 中,且程式碼仍舊;編譯器只是禁止除錯程式進入它的內容。

第二個 C# 新功能涉及 註釋,是根據 ECMA 標準新增的。C# 現在支援在使用“斜線和星號”符號(/**/)編寫的多行註釋中新增 XML 註釋。下面的 XML 註釋在 2003 版的 C# 編譯器中是合法的:

/**

這是註釋 */


此外,出於完整性的考慮(但實際上絕不推薦),程式設計師可以混合並匹配註釋樣式,同時仍然能夠編寫出有效的 XML 註釋程式碼。這樣,下面的這個註釋宣告現在也是合法的:

/**

這是註釋 */ ///


實現的改變

2003 版的 C# 編譯器和 2002 版也有微小的區別。在有些情況下,這些區別可能會導致程式碼無法編譯,或導致其執行方式與應執行的方式大相徑庭。

“Foreach”語句的改變

現在,foreach 語句可以動態地檢查它所迭代的資料結構中是否存在 IDisposable 介面。以前,編譯器從不動態地檢查 Idisposable 介面是否存在,除非從 GetEnumerator 返回的型別已實現了 IEnumerator 介面。然而,如果此型別對於實現 Idisposable 是靜態已知的,則編譯器將一直 Dispose。換句話說,如果迭代程式型別實現了列舉器設計,但沒有專門實現 IEnumerator 介面,編譯器就不會呼叫 Dispose 方法,除非 iterator 型別對於實現 IDisposable 介面是靜態已知的。

現在,編譯器在檢測是否存在 IDisposable 介面時,無論迭代程式型別是否實現 IEnumerator,都將呼叫 Dispose 方法(如果已實現)。在下面的示例中,Visual C# .NET 2002 編譯器未呼叫 Dispose 方法,但 Visual C# .NET 2003 編譯器呼叫了該方法:

abstract class Base { public int Current { get; } public bool MoveNext(); } class Derived: Base, IDisposable { // Base 和 IDisposable 的實現 } class MyClass { public Base GetEnumerator() { return new Derived(); } }


foreach 語句在某個集合中使用迭代時,它將執行 GetEnumerator 方法並接收轉換為 Base 型別的 Derived 例項作為它的迭代程式型別。當然,Base 型別無需為了呼叫它的 CurrentMoveNext 方法而實現 Ienumerator 介面。在早期編譯器中,Derived 型別的 Dispose 方法不被呼叫,因為它不實現 IEnumerator,並且類 Base 對於實現 Idisposable 不是靜態已知的。在新的編譯器中,Dispose 方法被呼叫,因為編譯器在所有 foreach 語句的迭代程式型別中檢查是否存在 Idisposable 介面。由於 GetEnumerator 呼叫的結果是一個轉換為 Base 型別的 Derived 型別,並且由於 Derived 型別實現 Idisposable 介面,因此編譯器動態檢查 Idisposable 介面是否存在,會導致對 Dispose 方法的呼叫。

屬性宣告的改變

ECMA C# 標準明確禁止為相應的屬性建立獲取和設定。實際上,C# 編譯器將屬性宣告轉換為獲取和設定函式,以便不支援屬性的語言也可以訪問資料。因此,下面的程式碼是無效的,因為編譯器會產生 get_Propset_Prop 方法,而這兩個方法與使用者宣告的方法發生衝突:

public class MyClass { public int Prop { get { } set { } } // 現在屬於函式 public int get_Prop() { } // 現在屬於非法函式 public void set_Prop(int val) { } }


以前,C# 編譯器允許建立此類函式,顯然這是一個錯誤。2003 版的 C# 編譯器糾正了這個錯誤。

作為此編譯器錯誤糾正的必然結果,C# 編譯器將不再允許顯式建立生成屬性的獲取和設定函式(如果將屬性定義為介面實現的結果)。在下面的示例中,2003 版的 C# 編譯器不再允許在 Derived 類中顯式實現 IMyInterface.get_PropIMyInterface.set_Prop 方法:

interface IMyInterface { public int Prop { get; set; } } public class Derived : IMyInterface { public int Prop { get { } set { } } // 非法 public int IMyInterface.get_Prop() { } // 非法 public void IMyInterface.set_Prop(int val) { } }


其他改變

C# 編譯器的早期版本允許不相容地使用屬性。2003 版的 C# 編譯器已經糾正了這些用法,因此更符合 ECMA 規範。首先是對 C# 編譯器進行了糾正,不允許在其引數列表中使用未在屬性類宣告中宣告為 public 的命名引數。例如,如果某個 AuthorAttribute 類是使用名為 authorName 的私有欄位建立的,則下面的語句在 C# 編譯器的早期版本中是允許的,但在 C# 2003 編譯器中卻會導致錯誤:

[Author(authorName="microsoftuser")] public class MyClass { }


第二,ObsoleteAttribute 現在可以應用到運算子,這樣程式設計師就可以使過載的運算子函式失效。最後,編譯器以前對於無法識別的屬性位置常常生成一個錯誤,而現在則根據 ECMA C# 規範的要求只生成一個警告。

另外,C# 編譯器以前接受使用者定義的移位運算子引數(<< 和 >>),而根據 ECMA C# 規範,這些引數是無效的。例如,移位運算子以前可以按以下方式進行宣告,即將封裝類的型別宣告為第二個運算元:

public class MyClass { public static MyClass operator <

按照規範,如果向左移位運算子被過載,則二進位制運算子的運算元列表中的第一個引數必須為封裝型別。同樣,如果向右移位運算子被過載,則二進位制運算子的運算元列表中的第二個引數必須為封裝型別。下面的程式碼示例演示了向左移位運算子的正確宣告方式:

public class MyClass { public static MyClass operator <

最後,還加入了幾個用於糾正編譯器錯誤的修復,包括:

  • 對顯式賦值演算法的糾正,使編譯器對於符合 ECMA C# 規範的程式碼不再報錯。
  • 列舉型別現在可以轉換為字元(詳見 ECMA C# 規範中的說明)。
  • 內部虛警告已被刪除,因為內部虛擬函式無法在程式集外被重寫。

小結

C# 編譯器以不同的方式實現了幾個功能,從而獲得了比前一版更高的。但這些改進不會影響對程式碼的編譯和執行:

  • 在迭代字串的元素時,foreach 語句現在使用字串的器而非列舉器模式,這樣使效能更佳。
  • 現在,C# 編譯器在處理浮點運算和十進位制數學運算方面更嚴格地遵循 ECMA C# 規範。
  • 幾個軟體錯誤已被修復,使控制流得到。

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

相關文章