博文
C# 语言规范--2.3.3 注释(2006-09-03 18:35:00)
摘要:支持两种形式的注释:单行注释和带分隔符的注释。单行注释以字符 // 开头并延续到源行的结尾。带分隔符的注释以字符 /* 开头,以字符 */ 结束。带分隔符的注释可以跨多行。
comment:(注释:)
single-line-comment(单行注释)
delimited-comment(带分隔符的注释)
single-line-comment:(单行注释:)
// input-charactersopt(// 输入字符可选)
input-characters:(输入字符:)
input-character(输入字符)
input-characters input-character(输入字符 输入字符)
input-character:(输入字符:)
除换行符外的任何 Unicode 字符
new-line-character:(换行符:)
回车符 (U+000D)
换行符 (U+000A)
行分隔符 (U+2028)
段落分隔符 (U+2029)
delimited-comment:(带分隔符的注释:)
/* delimited-comment-charactersopt */(/* 带分隔符的注释字符可选 */)
delimited-comment-characters:(带分隔符的注释字符:)
delimited-comment-character(带分隔符的注释字符)
delimited-comment-characters delimited-comment-character(带分隔符的注释字符 带分隔符的注释字符)
delimited-comment-character:(带分隔符的注释字符:)
not-asterisk(非星号)
* not-slash(* &nb......
C# 语言规范--2.3.2 空白(2006-09-03 18:34:00)
摘要:空白被定义为任何含 Unicode 类 Zs 的字符(包括空白字符)以及水平制表符、垂直制表符和换页符。
whitespace:(空白:)
任何含 Unicode 类 Zs 的字符
水平制表符 (U+0009)
垂直制表符 (U+000B)
换页符 (U+000C)
......
C# 语言规范--2.3.1 行结束符(2006-09-03 18:34:00)
摘要:行结束符将 C# 源文件的字符划分为行。
new-line:(新行:)
回车符 (U+000D)
换行符 (U+000A)
回车符 (U+000D) 后跟换行符 (U+000A)
行分隔符 (U+2028)
段落分隔符 (U+2029)
为了与添加文件尾标记的源代码编辑工具兼容,并能够以正确结束的行序列的形式查看源文件,下列转换按顺序应用到 C# 程序中的每个源文件:
如果源文件的最后一个字符为 Control-Z 字符 (U+001A),则删除此字符。
如果源文件非空并且源文件的最后一个字符不是回车符 (U+000D)、换行符 (U+000A)、行分隔符 (U+2028) 或段落分隔符 (U+2029),则将在源文件的结尾添加一个回车符 (U+000D)。
......
C# 语言规范--2.2.1 文法表示法(2006-09-03 18:34:00)
摘要:词法文法和句法文法用文法产生式来表示。每个文法产生式定义一个非结束符号和它可能的扩展(由非结束符或结束符组成的序列)。在文法产生式中,非结束符号显示为斜体,而结束符号显示为等宽字体。
文法产生式的第一行是该产生式所定义的非结束符号的名称,后跟一个冒号。每个后续的缩进行列出一个可能的扩展,它是以非结束符或结束符组成的序列的形式给出的。例如,产生式:
while-statement:(while 语句:)
while ( boolean-expression ) embedded-statement(while ( 布尔表达式 ) 嵌入语句)
定义了一个 while 语句,它是这样构成的:由标记 while 开始,后跟标记“(”、布尔表达式、标记“)”和嵌入的语句。
当有不止一个可能的非结束符号扩展时,列出这些可能的扩展(每个扩展单独占一行)。例如,产生式:
statement-list:(语句列表:)
statement(语句)
statement-list statement(语句列表 语句)
定义一个语句列表,它或仅含有一个语句,或由一个语句列表和随后跟着的一个语句组成。换言之,定义是递归的,语句列表由一个或多个语句组成。
一个符号若以下标“可选”作其后缀,就表明该符号是可选的。产生式:
block:(块:)
{ statement-listopt }({ 语句列表可选 })
是以下产生式的简短形式:
block:(块:)
{ }
{ statement-list }({ 语句列表&nb......
C# 语言规范--2.1 程序(2006-09-03 18:33:00)
摘要:C# 程序由一个或多个源文件(正规地应称为编译单元(第 9.1 节))组成。源文件是有序的 Unicode 字符序列。源文件与文件系统中的文件通常具有一对一的对应关系,但这种对应关系不是必需的。为实现最大的可移植性,建议这些文件在文件系统中应按 UTF-8 规范编码。
从概念上讲,程序的编译分三个步骤:
转换,这一步将用特定字符指令系统和编码方案编写的文件转换为 Unicode 字符序列。
词法分析,这一步将 Unicode 输入字符流转换为标记流。
句法分析,这一步将标记流转换为可执行代码。
......
C# 语言规范--1.14 属性(2006-09-03 18:33:00)
摘要:C# 是一种命令式语言,但像所有命令式语言一样,它具有某些声明性元素。例如,通过将类中的方法声明为 public、protected、internal、protected internal 或 private,指定它的可访问性。C# 使此功能一般化,以便程序员可以创造出一种新的声明性信息,将此声明性信息附加到各种程序实体,并在运行时检索此声明性信息。程序通过定义和使用属性(第 17 节)来描述这类额外的声明性信息。
例如,一个框架也许会定义一个可放置在程序元素(如类和方法)上的 HelpAttribute 属性,使开发人员能够提供从程序元素到其文档的映射。示例using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute: Attribute
{
public HelpAttribute(string url) {
this.url = url;
}
public string Topic = null;
private string url;
public string Url {
get { return url; }
}
}
定义了一个名为 HelpAttribute 的属性类,它具有一个定位参数 (string url) 和一个命名参数 (string Topic)。正如第 17.1 节中所解释的,该属性可以通过它的完整名称 HelpAttribute 或通过它的隐式简称 Help 引用。定位参数由该属性类的公共实例构造函数的形参定义,命名参数则由属性类的公共非静态读写字段和对应的属性定义。
示例[Help("http://www.microsoft.com/.../Class1.htm")]
public class Class1
{
[Help("http://www.microsoft.com/.../Class1.htm", Topic = "F")]
public void F() {}
}
显示 Help 属性的几种用法。
在运行时可以利用反射支持检索给定程序元素的属性信息。示例using System;
class Test
{......
C# 语言规范--1.13 版本控制(2006-09-03 18:32:00)
摘要:版本控制是一个过程,它以兼容的方式对组件进行不断的改进。如果依赖于早期版本的代码重新编译后可以适用于新版本,则组件的新版本与早期版本源代码兼容。相反,如果依赖于早期版本的应用程序不用重新编译即可适用于新版本,则组件的新版本为二进制兼容。
大多数语言根本不支持二进制兼容性,而且许多语言对促进源代码兼容性所做甚少。实际上,某些语言所含的缺陷使得用它开发出来的组件在不断的改进过程中,一般至少会使依赖于该组件的某些客户端代码失效。
例如,请看一个发布名为 Base 的类的基类作者的情况。在第一个版本中,Base 不包含任何 F 方法。名为 Derived 的组件从 Base 派生,并引入 F。此 Derived 类与它所依赖的 Base 类一起发布给客户,客户又部署到众多客户端和服务器。// Author A
namespace A
{
public class Base // version 1
{
}
}
// Author B
namespace B
{
class Derived: A.Base
{
public virtual void F() {
System.Console.WriteLine("Derived.F");
}
}
}
从这时起,开始产生版本问题。Base 的作者生成了一个拥有自己的 F 方法的新版本。// Author A
namespace A
{
public class Base // version 2
{
public virtual void F() { // added in version 2
System.Console.WriteLine("Base.F");
}
}
}
这个新版本的 Base 在源代码和二进制方面都应该与初始版本兼容。(如果仅添加一个新的方法就会产兼容性问题,则基类可能就永远不能改进了。)不幸的是,Base 中的新 F 使 Derived 的 F 的含义不清。Derived 是指重写 Base 的 F 吗?这看上去不太可能,因为编译 Derived 时,Base 还没有 F!......
C# 语言规范--1.12 命名空间和程序集(2006-09-03 18:32:00)
摘要:除了依赖于几个系统提供的类(如 System.Console),到目前为止介绍的程序都是独立存在的。但更常见的情况是:实际的应用程序由若干不同的部分组成,每个部分分别进行编译。例如,企业级应用程序可能依赖于若干不同的组件,其中包括某些内部开发的组件和某些从独立软件供应商处购买的组件。
命名空间和程序集有助于开发基于组件的系统。命名空间提供一个逻辑组织体系。命名空间既用作程序的“内部”组织体系,也用作“外部”组织体系(一种表示向其他程序公开程序元素的途径)。
程序集用于物理打包和部署。程序集可以包含类型、用于实现这些类型的可执行代码以及对其他程序集的引用。
有两种主要的程序集:应用程序和库。应用程序有一个主入口点,通常具有 .exe 文件扩展名;而库没有主入口点,通常具有 .dll 文件扩展名。
为了说明命名空间和程序集的使用,本节再次以前面介绍的“hello, world”程序为例,并将它分为两个部分:提供消息的类库和显示消息的控制台应用程序。
这个类库仅含一个名为 HelloMessage 的类。示例// HelloLibrary.cs
namespace Microsoft.CSharp.Introduction
{
public class HelloMessage
{
public string Message {
get {
return "hello, world";
}
}
}
}
显示了名为 Microsoft.CSharp.Introduction 的命名空间中的 HelloMessage 类。HelloMessage 类提供一个名为 Message 的只读属性。命名空间可以嵌套,而声明namespace Microsoft.CSharp.Introduction
{...}
仅是若干层命名空间嵌套的简写形式。若不简化,则应该像下面这样声明:namespace Microsoft
{
namespace CSharp
{
namespace Introduction
{...}
}
}
将“hello, world”组件化的下一个步骤是编写使用 Hel......
C# 语言规范--1.11 枚举(2006-09-03 18:32:00)
摘要:枚举类型声明为一组相关的符号常数定义了一个类型名称。枚举用于“多项选择”场合,就是程序运行时从编译时已经设定的固定数目的“选择”中做出决定。
示例enum Color
{
Red,
Blue,
Green
}
class Shape
{
public void Fill(Color color) {
switch(color) {
case Color.Red:
...
break;
case Color.Blue:
...
break;
case Color.Green:
...
break;
default:
break;
}
}
}
显示了一个 Color 枚举和一个使用此枚举的方法。Fill 方法的签名清楚地表明可以用给定的颜色之一来填充形状。
使用枚举胜过使用整数常数(在没有枚举的语言中很常见),这是因为使用枚举使代码更具可读性和自归档。代码的自归档特性还使开发工具可以帮助代码编写和其他“设计器”活动。例如,对参数类型使用 Color 而不用 int 使聪明的代码编辑器能够建议 Color 值。
......
C# 语言规范--1.10 委托(2006-09-03 18:31:00)
摘要:委托适用于那种在某些其他语言中需用函数指针来解决的情况(场合)。但是,与函数指针不同,委托是面向对象和类型安全的。
委托声明定义一个类,它是从 System.Delegate 类派生的类。委托实例封装了一个调用列表,该列表列出了一个或多个方法,每个方法称为一个可调用实体。对于实例方法,可调用实体由一个实例和该实例的方法组成。对于静态方法,可调用实体仅由一个方法组成。如果用一组合适的参数来调用一个委托实例,则该委托实例所封装的每个可调用实体都会被调用,并且用的都是上述的同一组参数。
委托实例的一个有趣且有用的属性是:它既不知道也不关心有关它所封装的方法所属的类的种种详情;对它来说最重要的是这些方法与该委托的类型兼容。这使委托非常适合“匿名”调用。这是一个强大的功能。
定义和使用委托分三个步骤:声明、实例化和调用。委托用委托声明语法来声明。示例delegate void SimpleDelegate();
声明一个名为 SimpleDelegate 的委托,它不带参数并且不返回任何结果。
示例class Test
{
static void F() {
System.Console.WriteLine("Test.F");
}
static void Main() {
SimpleDelegate d = new SimpleDelegate(F);
d();
}
}
创建一个 SimpleDelegate 实例,然后立即调用它。
这样做(为方法创建一个委托,然后立即通过这个委托调用该方法)并没有太大意义,因为直接调用方法更简单。当涉及它的匿名特性时,委托才真正显示出它的效用。示例void MultiCall(SimpleDelegate d, int count) {
for (int i = 0; i < count; i++) {
d();
}
}
显示了一个重复调用 SimpleDelegate 的 MultiCall 方法。MultiCall 方法不知道也不在乎 SimpleDelegate 的目标方法的类型、该方法所具有的可访问性或者该方法是否为静态。对它来说最重要的是目标方法与 SimpleDelegate 兼容。
&nbs......