【C#语言规范版本5.0学习】3 基本概念

应用程序启动

具有入口点 (entry point) 的程序集称为应用程序 (application)。应用程序运行时,将创建新的应用程序域 (application domain)。同一台计算机上可能会同时运行着同一个应用程序的若干个实例,此时,每一个实例都拥有各自的应用程序域。

应用程序域用作应用程序状态的容器,以此隔离应用程序。应用程序域作为应用程序中和它使用的类库中所定义的类型的容器和边界。同一个类型若被加载到不同的应用程序域中就成为各自独立的客体,由它们在各自应用程序域中产生的实例亦不可直接共享。例如,对于这些类型的静态变量,每个应用程序域都有自己的副本,并且这些类型的静态构造函数在每个应用程序域中也要(最多)运行一次。关于如何处理程序域的创建和销毁,各实现可以按具体情况确定自己的策略或机制。

当执行环境调用指定的方法(称为应用程序的入口点)时发生应用程序启动 (application startup)。此入口点方法总是被命名为 Main,可以具有下列签名之一:

static void Main() {...}
static void Main(string[] args) {...}
static int Main() {...}
static int Main(string[] args) {...}

如上所示,入口点可以选择返回一个 int 值。此返回值用于应用程序终止。

入口点可以包含一个形参(可选)。该参数可以具有任意名称,但参数的类型必须为 string[]。如果存在形参,执行环境会创建并传递一个包含命令行实参的 string[] 实参,这些命令行实参是在启动应用程序时指定的。string[] 参数永远不能为 null,但如果没有指定命令行参数,它的长度可以为零。

由于 C# 支持方法重载,因此类或结构可以包含某个方法的多个定义(前提是每个定义有不同的签名)。 但在一个程序内,没有任何类或结构可以包含一个以上的名为 Main 的方法,因为 Main 的定义限定它只能被用作应用程序的入口点。允许使用 Main 的其他重载版本,前提是它们具有一个以上的参数,或者它们的唯一参数的类型不是 string[]。

应用程序可由多个类或结构组成。在这些类或结构中,可能会有若干个拥有自己的 Main 方法,因为 Main 的定义限定它只能被用作应用程序的入口点。这样的情况下,必须利用某种外部机制(如命令行编译器的选项)来选择其中一个 Main 方法用作入口点。

在 C# 中,每个方法都必须定义为类或结构的成员。通常,方法的已声明可访问性由其声明中指定的访问修饰符确定。同样,类型的已声明可访问性由其声明中指定的访问修饰符确定。为了能够调用给定类型的给定方法,类型和成员都必须是可访问的。然而,应用程序入口点是一种特殊情况。具体而言,执行环境可以访问应用程序的入口点,无论它本身的可访问性和封闭它的类型的可访问性是如何在声明语句中设置的。

应用程序入口点方法不能位于泛型类声明中。在所有其他方面,入口点方法的行为与非入口点方法类似。

应用程序终止

应用程序终止 (application termination) 将控制返回给执行环境。如果应用程序的入口点 (entry point) 方法的返回类型为 int,则返回的值用作应用程序的终止状态代码 (termination status code)。此代码的用途是允许与执行环境进行关于应用程序运行状态(成功或失败)的通信。

如果入口点方法的返回类型为 void,那么在到达终止该方法的右大括号 (}),或者执行不带表达式的 return 语句时,将产生终止状态代码 0。 在应用程序终止之前,将调用其中还没有被垃圾回收的所有对象的析构函数,除非已将这类清理功能设置为取消使用(例如,通过调用库方法 GC.SuppressFinalize)。

声明

C# 程序中的声明定义程序的构成元素。C# 程序是用命名空间组织起来的,一个命名空间可以包含类型声明和嵌套的命名空间声明。

类型声明用于定义类、结构、接口、枚举和委托。在一个类型声明中可以使用哪些类型作为其成员,取决于该类型声明的形式。例如,类声明可以包含常量声明、字段声明、方法声明、属性声明、事件声明、索引器声明、运算符声明、实例构造函数声明、静态构造函数声明、析构函数声明和嵌套类型声明。 一个声明在它自已所属的那个声明空间 (declaration space) 中定义一个名称。除非是重载成员,否则,在同一个声明空间下若有两个以上的声明语句声明了具有相同名称的成员,就会产生编译时错误。同一个声明空间内绝不能包含不同类型的同名成员。例如,声明空间绝不能包含同名的字段和方法。 有若干种不同类型的声明空间,如下所述。

 在程序的所有源文件中,namespace-member-declaration 若没有被置于任何一个 namespacedeclaration 下,则属于一个称为全局声明空间 (global declaration space) 的组合声明空间。

 在程序的所有源文件中,一个 namespace-member-declaration 若在 namespace-declaration 中具有相同的完全限定的命名空间名称,它就属于一个组合声明空间。

 每个类、结构或接口声明创建一个新的声明空间。名称将通过 class-member-declaration、structmember-declaration、interface-member-declarationtype-parameter 引入此声明空间。除了重载实例构造函数声明和静态构造函数声明外,类或结构不能包含与该类或结构同名的成员声明。类、结构或接口允许声明重载方法和索引器另外,类或结构允许重载实例构造函数和运算符的声明。例如, 类、结构或接口可以包含多个同名的方法声明,前提是这些方法声明的签名不同。注意,基类与类的声明空间无关,基接口与接口的声明空间无关。因此,允许在派生类或接口内声明与所继承的成员同名的成员。我们说这类成员隐藏 (hide) 了它们继承的那些成员。

 每个委托声明创建一个新的声明空间。名称通过形参(fixed-parameter 和 parameter-array)和 typeparameter 引入此声明空间。

 每个枚举声明创建一个新的声明空间。名称通过 enum-member-declarations 引入此声明空间。

 每个方法声明、索引器声明、运算符声明、实例构造函数声明和匿名函数均创建一个称为局部变量声明空间 (local variable declaration space) 的新声明空间。名称将通过形参(fixed-parameterparameter-array)和 type-parameter 引入此声明空间。函数成员或匿名函数的主体(如果有)将视为嵌套在局部变量声明空间中。如果局部变量声明空间和嵌套的局部变量声明空间包含具有相同名称的元素,则会发生错误。因此,在嵌套声明空间中不可能声明与封闭它的声明空间中的局部变量或常量同名的局部变量或常量。只要两个声明空间彼此互不包含,这两个声明空间就可以包含同名的元素

 每个 block 或 switch-block 以及 for、foreach 和 using 语句都会为局部变量和局部常量创建一个局部变量声明空间。名称将通过 local-variable-declarationlocal-constant-declaration 引入此声明空间。 请注意,作为函数成员的主体或匿名函数的主体出现或出现在该主体之中的块,将嵌套在这些函数为其参数声明的局部变量声明空间中。因此,如果某个方法的局部变量和参数具有相同名称,则会发生错误。

每个 block 或 switch-block 都为标签创建一个单独的声明空间。名称将通过 labeled-statement 引入此 声明空间,并通过 goto-statement 进行引用。块的标签声明空间可包含任何嵌套块。因此,在嵌套块 中不可能声明与封闭它的块中的标签同名的标签。 声明名称的文本顺序通常不重要。具体而言,声明和使用命名空间、常量、方法、属性、事件、索引器、 运算符、实例构造函数、析构函数、静态构造函数和类型时,文本顺序并不重要。

在下列情况下声明顺序非常重要:

 字段声明和局部变量声明的声明顺序确定其初始值设定项(如果有)的执行顺序。

 在使用局部变量前必须先定义它们。

 当省略 constant-expression 值时,枚举成员声明的声明顺序非常重要。

命名空间的声明空间是“开放式的”,两个具有相同的完全限定名的命名空间声明提供相同的声明空间。 例如

namespace Megacorp.Data
{
class Customer
{
...
}
}
namespace Megacorp.Data
{
class Order
{
...
}
}

上面的两个命名空间声明为同一声明空间提供了成员,在本例中它们分别声明了具有完全限定名 Megacorp.Data.Customer 和 Megacorp.Data.Order 的两个类。由于两个声明共同构成同一个声明空间,因此如果每个声明中都包含一个同名类的声明,则将导致编译时错误。 正如上面所述,块的声明空间包括所有嵌套块。因此,在下面的示例中,F 和 G 方法导致编译时错误, 因为名称 i 是在外部块中声明的,不能在内部块中重新声明。但方法 H 和 I 都是有效的,因为这两个 i 是在单独的非嵌套块中声明的。

class A
{
void F() {
int i = 0;
if (true) {
int i = 1;
}
}
void G() {
if (true) {
int i = 0;
}
int i = 1;
}
void H() {
if (true) {
int i = 0;
}
if (true) {
int i = 1;
}
}
void I() {
for (int i = 0; i < 10; i++)
H();
for (int i = 0; i < 10; i++)
H();
}
}

 

posted @ 2021-02-05 16:39  TechSingularity  阅读(91)  评论(0编辑  收藏  举报