来源:www.cncfan.com | 2006-1-12 | (有1877人读过)
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# 编译器中是合法的:
/** 这是 注释
*/
此外,出于完整性的考虑(但实际上绝不推荐),程序员可以混合并匹配注释样式,同时仍然能够编写出有效的 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 类型无需为了调用它的 Current 和 MoveNext 方法而实现 Ienumerator 接口。在早期编译器中,Derived 类型的 Dispose 方法不被调用,因为它不实现 IEnumerator,并且类 Base 对于实现 Idisposable 不是静态已知的。在新的编译器中,Dispose 方法被调用,因为编译器在所有 foreach 语句的迭代程序类型中检查是否存在 Idisposable 接口。由于 GetEnumerator 调用的结果是一个转换为 Base 类型的 Derived 类型,并且由于 Derived 类型实现 Idisposable 接口,因此编译器动态检查 Idisposable 接口是否存在,会导致对 Dispose 方法的调用。
|