Visual C# .NET 2003 语言的改变
Prashant Sridharan
Microsoft Corporation
2002年12月30日
適用于:
Microsoft Visual Studio? C# 2003
摘要:為了與歐洲計算機制造商協會 (ECMA) 的 C# 規范完全兼容,Microsoft Corporation 對 C# 編譯器的實現進行了幾處改動。這些改動將在多方面影響現有的代碼,因此用戶必須檢查他們的代碼以確保這些代碼符合 C# 編程語言必需的和推薦的使用要求。
目錄
背景
C# 語言的新功能
實現的改變
小結
背景
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.ProcessCommand();
c.Close();
}
}
然而,#line hidden 指令并不隱藏編譯器錯誤。當然,編譯器仍然將代碼編譯到 IL 中,且代碼仍舊執行;編譯器只是禁止調試程序進入它的內容。
第二個 C# 新功能涉及 XML 注釋,是根據 ECMA 標準添加的。C# 現在支持在使用“斜線和星號”符號(/* 和 */)編寫的多行注釋中添加 XML 注釋。下面的 XML 注釋在 2003 版的 C# 編譯器中是合法的:
/**
<summary>這是
注釋
</summary>
*/
此外,出于完整性的考慮(但實際上絕不推薦),程序員可以混合并匹配注釋樣式,同時仍然能夠編寫出有效的 XML 注釋代碼。這樣,下面的這個注釋聲明現在也是合法的:
/**
<summary>這是
注釋
*/
/// </summary>
實現的改變
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 類型無需為了調用它的 Current 和 MoveNext 方法而實現 Ienumerator 接口。在早期編譯器中,Derived 類型的 Dispose 方法不被調用,因為它不實現 IEnumerator,并且類 Base 對于實現 Idisposable 不是靜態已知的。在新的編譯器中,Dispose 方法被調用,因為編譯器在所有 foreach 語句的迭代程序類型中檢查是否存在 Idisposable 接口。由于 GetEnumerator 調用的結果是一個轉換為 Base 類型的 Derived 類型,并且由于 Derived 類型實現 Idisposable 接口,因此編譯器動態檢查 Idisposable 接口是否存在,會導致對 Dispose 方法的調用。
屬性聲明的改變
ECMA C# 標準明確禁止為相應的屬性創建獲取和設置函數。實際上,C# 編譯器將屬性聲明轉換為獲取和設置函數,以便不支持屬性的語言也可以訪問數據。因此,下面的代碼是無效的,因為編譯器會產生 get_Prop 和 set_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_Prop 和 IMyInterface.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 <<(int I, MyClass c)
{
}
public static void Main()
{
}
}
按照規范,如果向左移位運算符被重載,則二進制運算符的操作數列表中的第一個參數必須為封裝類型。同樣,如果向右移位運算符被重載,則二進制運算符的操作數列表中的第二個參數必須為封裝類型。下面的代碼示例演示了向左移位運算符的正確聲明方式:
public class MyClass
{
public static MyClass operator <<( MyClass c, int i)
{
}
public static void Main()
{
}
}
最后,還加入了幾個用于糾正編譯器錯誤的修復,包括:
對顯式賦值算法的糾正,使編譯器對于符合 ECMA C# 規范的代碼不再報錯。
枚舉類型現在可以轉換為字符(詳見 ECMA C# 規范中的說明)。
內部虛警告已被刪除,因為內部虛函數無法在程序集外被重寫。
小結
C# 編譯器以不同的方式實現了幾個功能,從而獲得了比前一版更高的性能。但這些改進不會影響對代碼的編譯和執行:
在迭代字符串的元素時,foreach 語句現在使用字符串的索引器而非枚舉器模式,這樣使性能更佳。
現在,C# 編譯器在處理浮點運算和十進制數學運算方面更嚴格地遵循 ECMA C# 規范。
幾個軟件錯誤已被修復,使控制流得到優化。
總結
以上是生活随笔為你收集整理的Visual C# .NET 2003 语言的改变的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 提高IIS网站服务器的效率的八种方法 (
- 下一篇: XML的二十个热点问题