基本概念Basic concepts

应用程序启动Application Startup

具有入口点的程序集称为应用程序An assembly that has an entry point is called an application. 当应用程序运行时,将创建一个新的应用程序域When an application is run, a new application domain is created. 同一台计算机上可以同时存在多个不同的应用程序实例,每个实例都有自己的应用程序域。Several different instantiations of an application may exist on the same machine at the same time, and each has its own application domain.

应用程序域通过充当应用程序状态的容器来实现应用程序隔离。An application domain enables application isolation by acting as a container for application state. 应用程序域充当应用程序中定义的类型和它所使用的类库的容器和边界。An application domain acts as a container and boundary for the types defined in the application and the class libraries it uses. 加载到一个应用程序域中的类型不同于加载到另一个应用程序域中的相同类型,并且不会在应用程序域之间直接共享对象的实例。Types loaded into one application domain are distinct from the same type loaded into another application domain, and instances of objects are not directly shared between application domains. 例如,每个应用程序域都有自己的静态变量副本用于这些类型,并且每个应用程序域最多运行一次类型的静态构造函数。For instance, each application domain has its own copy of static variables for these types, and a static constructor for a type is run at most once per application domain. 实现可自由提供特定于实现的策略,也可以创建和销毁应用程序域。Implementations are free to provide implementation-specific policy or mechanisms for the creation and destruction of application domains.

当执行环境调用指定方法(称为应用程序的入口点)时,将发生应用程序启动Application startup occurs when the execution environment calls a designated method, which is referred to as the application's entry point. 此入口点方法始终命名为 Main,可以具有以下签名之一:This entry point method is always named Main, and can have one of the following signatures:

static void Main() {...}

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

static int Main() {...}

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

如图所示,入口点可以选择返回 @no__t 0 值。As shown, the entry point may optionally return an int value. 此返回值用于应用程序终止(应用程序终止)。This return value is used in application termination (Application termination).

入口点还可以有一个形参。The entry point may optionally have one formal parameter. 参数可以具有任何名称,但参数的类型必须为 string[]The parameter may have any name, but the type of the parameter must be string[]. 如果正式参数存在,则执行环境将创建并传递一个 @no__t 的参数,该参数包含在启动应用程序时指定的命令行参数。If the formal parameter is present, the execution environment creates and passes a string[] argument containing the command-line arguments that were specified when the application was started. @No__t 参数决不会为 null,但如果未指定命令行参数,则其长度可能为零。The string[] argument is never null, but it may have a length of zero if no command-line arguments were specified.

由于C#支持方法重载,因此类或结构可能包含某些方法的多个定义,前提是每个定义具有不同的签名。Since C# supports method overloading, a class or struct may contain multiple definitions of some method, provided each has a different signature. 但是,在一个程序中,任何类或结构都不能包含多个称为 @no__t 的方法,它的定义限定它用作应用程序入口点。However, within a single program, no class or struct may contain more than one method called Main whose definition qualifies it to be used as an application entry point. 但允许 @no__t 的其他重载版本-0,但前提是它们具有多个参数,或者其唯一参数不是类型 string[]Other overloaded versions of Main are permitted, however, provided they have more than one parameter, or their only parameter is other than type string[].

应用程序可以由多个类或结构组成。An application can be made up of multiple classes or structs. 其中的多个类或结构可能包含一个名为 @no__t 的方法,该方法的定义将其限定为作为应用程序入口点使用。It is possible for more than one of these classes or structs to contain a method called Main whose definition qualifies it to be used as an application entry point. 在这种情况下,必须使用外部机制(例如命令行编译器选项)来选择其中一个 Main 方法作为入口点。In such cases, an external mechanism (such as a command-line compiler option) must be used to select one of these Main methods as the entry point.

在C#中,每个方法都必须定义为类或结构的成员。In C#, every method must be defined as a member of a class or struct. 通常,方法的声明的可访问性(已声明的可访问性)由其声明中指定的访问修饰符(访问修饰符)确定,并且类似于类型的声明的可访问性由在其声明中指定的访问修饰符。Ordinarily, the declared accessibility (Declared accessibility) of a method is determined by the access modifiers (Access modifiers) specified in its declaration, and similarly the declared accessibility of a type is determined by the access modifiers specified in its declaration. 为了使给定类型的给定方法可调用,该类型和成员都必须可访问。In order for a given method of a given type to be callable, both the type and the member must be accessible. 但是,应用程序入口点是一种特殊情况。However, the application entry point is a special case. 具体而言,执行环境可以访问应用程序的入口点,无论其声明的可访问性以及其封闭类型声明的声明的可访问性。Specifically, the execution environment can access the application's entry point regardless of its declared accessibility and regardless of the declared accessibility of its enclosing type declarations.

应用程序入口点方法不能在泛型类声明中。The application entry point method may not be in a generic class declaration.

在所有其他方面,入口点方法的行为类似于非入口点的行为。In all other respects, entry point methods behave like those that are not entry points.

应用程序终止Application termination

应用程序终止会向执行环境返回控制权。Application termination returns control to the execution environment.

如果应用程序的入口点方法的返回类型为 int,则返回的值将用作应用程序的终止状态代码If the return type of the application's entry point method is int, the value returned serves as the application's termination status code. 此代码的目的是允许向执行环境进行成功或失败的通信。The purpose of this code is to allow communication of success or failure to the execution environment.

如果入口点方法的返回类型为 void,则到达右大括号(@no__t 为-1)以终止该方法,或执行没有表达式的 return 语句会导致终止状态代码 @no__t 为3。If the return type of the entry point method is void, reaching the right brace (}) which terminates that method, or executing a return statement that has no expression, results in a termination status code of 0.

在应用程序终止之前,将调用其所有尚未进行垃圾回收的对象的析构函数,除非已取消此类清理(例如,通过调用库方法 GC.SuppressFinalize)。Prior to an application's termination, destructors for all of its objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example).

声明Declarations

C#程序中的声明定义程序的构成元素。Declarations in a C# program define the constituent elements of the program. C#使用命名空间(命名空间)对程序进行组织,其中可以包含类型声明和嵌套命名空间声明。C# programs are organized using namespaces (Namespaces), which can contain type declarations and nested namespace declarations. 类型声明(类型声明)用于定义类()、结构(结构)、接口(接口)、枚举(枚举)和委托(委托)。Type declarations (Type declarations) are used to define classes (Classes), structs (Structs), interfaces (Interfaces), enums (Enums), and delegates (Delegates). 类型声明中允许的成员种类取决于类型声明的形式。The kinds of members permitted in a type declaration depend on the form of the type declaration. 例如,类声明可以包含常量(常量)、字段(字段)、方法(方法)、属性(属性)、事件(事件)、索引器(索引器)的声明,运算符(运算符)、实例构造函数(实例构造函数)、静态构造函数(静态构造函数)、析构函数(析构函数)和嵌套类型(嵌套类型)。For instance, class declarations can contain declarations for constants (Constants), fields (Fields), methods (Methods), properties (Properties), events (Events), indexers (Indexers), operators (Operators), instance constructors (Instance constructors), static constructors (Static constructors), destructors (Destructors), and nested types (Nested types).

声明定义声明空间中声明所属的名称。A declaration defines a name in the declaration space to which the declaration belongs. 除重载成员(签名和重载)外,具有两个或多个将在声明空间中引入同名成员的声明是编译时错误。Except for overloaded members (Signatures and overloading), it is a compile-time error to have two or more declarations that introduce members with the same name in a declaration space. 声明空间不能包含具有相同名称的不同类型的成员。It is never possible for a declaration space to contain different kinds of members with the same name. 例如,声明空间不能包含具有相同名称的字段和方法。For example, a declaration space can never contain a field and a method by the same name.

有几种不同类型的声明空间,如下所述。There are several different types of declaration spaces, as described in the following.

  • 在程序的所有源文件中,不带封闭namespace_declarationnamespace_member_declaration是单个合并声明空间的成员,称为全局声明空间Within all source files of a program, namespace_member_declarations with no enclosing namespace_declaration are members of a single combined declaration space called the global declaration space.
  • 在程序的所有源文件中,在具有相同完全限定的命名空间名称的namespace_declaration中的namespace_member_declarations 是单个组合声明空间的成员。Within all source files of a program, namespace_member_declarations within namespace_declarations that have the same fully qualified namespace name are members of a single combined declaration space.
  • 每个类、结构或接口声明都创建新的声明空间。Each class, struct, or interface declaration creates a new declaration space. 通过class_member_declarations、 struct_member_declarations、 interface_member_declarationtype_parameter将名称引入到此声明空间。Names are introduced into this declaration space through class_member_declarations, struct_member_declarations, interface_member_declarations, or type_parameters. 除了重载实例构造函数声明和静态构造函数声明,类或结构不能包含与类或结构同名的成员声明。Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. 类、结构或接口允许声明重载方法和索引器。A class, struct, or interface permits the declaration of overloaded methods and indexers. 此外,类或结构允许声明重载实例构造函数和运算符。Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. 例如,类、结构或接口可能包含多个具有相同名称的方法声明,前提是这些方法声明在其签名中不同(签名和重载)。For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature (Signatures and overloading). 请注意,基类不涉及类的声明空间,并且基接口不涉及接口的声明空间。Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. 因此,允许派生类或接口声明与继承成员同名的成员。Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. 这种成员被称为隐藏继承成员。Such a member is said to hide the inherited member.
  • 每个委托声明都将创建一个新的声明空间。Each delegate declaration creates a new declaration space. 通过形参(fixed_parameters 和parameter_arrays)和type_parameter将名称引入到此声明空间。Names are introduced into this declaration space through formal parameters (fixed_parameters and parameter_arrays) and type_parameters.
  • 每个枚举声明都将创建一个新的声明空间。Each enumeration declaration creates a new declaration space. 通过enum_member_declarations将名称引入此声明空间。Names are introduced into this declaration space through enum_member_declarations.
  • 每个方法声明、索引器声明、运算符声明、实例构造函数声明和匿名函数都会创建一个名为局部变量声明空间的新声明空间。Each method declaration, indexer declaration, operator declaration, instance constructor declaration and anonymous function creates a new declaration space called a local variable declaration space. 通过形参(fixed_parameters 和parameter_arrays)和type_parameter将名称引入到此声明空间。Names are introduced into this declaration space through formal parameters (fixed_parameters and parameter_arrays) and type_parameters. 函数成员或匿名函数(如果有)的主体被视为嵌套在局部变量声明空间内。The body of the function member or anonymous function, if any, is considered to be nested within the local variable declaration space. 局部变量声明空间和嵌套局部变量声明空间包含具有相同名称的元素是错误的。It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. 因此,在嵌套的声明空间内,不能在封闭声明空间中声明与本地变量或常量同名的局部变量或常数。Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space. 可能有两个声明空间包含具有相同名称的元素,前提是两个声明空间都不包含另一个。It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other.
  • 每个blockswitch_block以及forforeachusing语句均为局部变量和局部常量创建一个局部变量声明空间。Each block or switch_block , as well as a for, foreach and using statement, creates a local variable declaration space for local variables and local constants . 通过local_variable_declarations 和local_constant_declaration将名称引入此声明空间。Names are introduced into this declaration space through local_variable_declarations and local_constant_declarations. 请注意,在函数成员或匿名函数的主体中发生的块嵌套在这些函数为其参数声明的局部变量声明空间内。Note that blocks that occur as or within the body of a function member or anonymous function are nested within the local variable declaration space declared by those functions for their parameters. 因此,例如,具有本地变量和同名参数的方法是错误的。Thus it is an error to have e.g. a method with a local variable and a parameter of the same name.
  • 每个blockswitch_block为标签创建一个单独的声明空间。Each block or switch_block creates a separate declaration space for labels. 通过labeled_statement将名称引入此声明空间,并通过goto_statement引用名称。Names are introduced into this declaration space through labeled_statements, and the names are referenced through goto_statements. 块的标签声明空间包括任何嵌套块。The label declaration space of a block includes any nested blocks. 因此,在嵌套块中,不能声明与封闭块中的标签具有相同名称的标签。Thus, within a nested block it is not possible to declare a label with the same name as a label in an enclosing block.

声明名称的文本顺序通常不重要。The textual order in which names are declared is generally of no significance. 特别是,文本顺序对于命名空间、常量、方法、属性、事件、索引器、运算符、实例构造函数、析构函数、静态构造函数和类型的声明和使用并不重要。In particular, textual order is not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors, and types. 声明顺序在以下方面非常重要:Declaration order is significant in the following ways:

  • 字段声明和局部变量声明的声明顺序决定了其初始值设定项(如果有)的执行顺序。Declaration order for field declarations and local variable declarations determines the order in which their initializers (if any) are executed.
  • 局部变量必须在使用之前定义(范围)。Local variables must be defined before they are used (Scopes).
  • 省略constant_expression值时,枚举成员声明(enum 成员)的声明顺序很重要。Declaration order for enum member declarations (Enum members) is significant when constant_expression values are omitted.

命名空间的声明空间为 "open 已结束",两个具有相同完全限定名称的命名空间声明会导致相同的声明空间。The declaration space of a namespace is "open ended", and two namespace declarations with the same fully qualified name contribute to the same declaration space. 例如For example

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

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

上面的两个命名空间声明为同一声明空间提供,在此示例中,声明两个具有完全限定名称的类 Megacorp.Data.CustomerMegacorp.Data.OrderThe two namespace declarations above contribute to the same declaration space, in this case declaring two classes with the fully qualified names Megacorp.Data.Customer and Megacorp.Data.Order. 由于这两个声明涉及到相同的声明空间,因此,如果每个声明都包含具有相同名称的类的声明,则会导致编译时错误。Because the two declarations contribute to the same declaration space, it would have caused a compile-time error if each contained a declaration of a class with the same name.

如上所述,块的声明空间包括任何嵌套块。As specified above, the declaration space of a block includes any nested blocks. 因此,在下面的示例中,F 和 @no__t 1 方法会导致编译时错误,因为名称 i 是在外部块中声明的,不能在内部块中重新声明。Thus, in the following example, the F and G methods result in a compile-time error because the name i is declared in the outer block and cannot be redeclared in the inner block. 但是,@no__t 的 @no__t 方法有效,因为这两个 i 在单独的非嵌套块中声明。However, the H and I methods are valid since the two i's are declared in separate non-nested blocks.

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();
    }
}

成员Members

命名空间和类型具有成员Namespaces and types have members. 实体的成员通常通过使用以实体引用开头的限定名称来提供,后跟一个 "." 标记,后跟成员的名称。The members of an entity are generally available through the use of a qualified name that starts with a reference to the entity, followed by a "." token, followed by the name of the member.

类型成员既可以在类型声明中声明,也可以从类型的基类继承Members of a type are either declared in the type declaration or inherited from the base class of the type. 当类型从基类继承时,基类的所有成员(实例构造函数、析构函数和静态构造函数除外)将成为派生类型的成员。When a type inherits from a base class, all members of the base class, except instance constructors, destructors and static constructors, become members of the derived type. 基类成员的声明的可访问性不会控制是否继承成员,继承扩展到任何不是实例构造函数、静态构造函数或析构函数的成员。The declared accessibility of a base class member does not control whether the member is inherited—inheritance extends to any member that isn't an instance constructor, static constructor, or destructor. 但是,在派生的类型中,可能无法访问继承的成员,这可能是由于其声明的可访问性(已声明可访问性)或由类型本身中的声明隐藏(通过继承隐藏)。However, an inherited member may not be accessible in a derived type, either because of its declared accessibility (Declared accessibility) or because it is hidden by a declaration in the type itself (Hiding through inheritance).

命名空间成员Namespace members

没有封闭命名空间的命名空间和类型是全局命名空间的成员。Namespaces and types that have no enclosing namespace are members of the global namespace. 这直接对应于全局声明空间中声明的名称。This corresponds directly to the names declared in the global declaration space.

命名空间中声明的命名空间和类型是该命名空间的成员。Namespaces and types declared within a namespace are members of that namespace. 这直接对应于命名空间声明空间中声明的名称。This corresponds directly to the names declared in the declaration space of the namespace.

命名空间没有任何访问限制。Namespaces have no access restrictions. 不能声明私有、受保护的或内部命名空间,并且命名空间名称始终是可公开访问的。It is not possible to declare private, protected, or internal namespaces, and namespace names are always publicly accessible.

结构成员Struct members

结构的成员是在结构中声明的成员和从该结构的直接基类继承的成员 System.ValueType 和间接基类 @no__t 为-1。The members of a struct are the members declared in the struct and the members inherited from the struct's direct base class System.ValueType and the indirect base class object.

简单类型的成员直接与简单类型化名为的结构类型成员相对应:The members of a simple type correspond directly to the members of the struct type aliased by the simple type:

  • @No__t 的成员是 System.SByte 结构的成员。The members of sbyte are the members of the System.SByte struct.
  • @No__t 的成员是 System.Byte 结构的成员。The members of byte are the members of the System.Byte struct.
  • @No__t 的成员是 System.Int16 结构的成员。The members of short are the members of the System.Int16 struct.
  • @No__t 的成员是 System.UInt16 结构的成员。The members of ushort are the members of the System.UInt16 struct.
  • @No__t 的成员是 System.Int32 结构的成员。The members of int are the members of the System.Int32 struct.
  • @No__t 的成员是 System.UInt32 结构的成员。The members of uint are the members of the System.UInt32 struct.
  • @No__t 的成员是 System.Int64 结构的成员。The members of long are the members of the System.Int64 struct.
  • @No__t 的成员是 System.UInt64 结构的成员。The members of ulong are the members of the System.UInt64 struct.
  • @No__t 的成员是 System.Char 结构的成员。The members of char are the members of the System.Char struct.
  • @No__t 的成员是 System.Single 结构的成员。The members of float are the members of the System.Single struct.
  • @No__t 的成员是 System.Double 结构的成员。The members of double are the members of the System.Double struct.
  • @No__t 的成员是 System.Decimal 结构的成员。The members of decimal are the members of the System.Decimal struct.
  • @No__t 的成员是 System.Boolean 结构的成员。The members of bool are the members of the System.Boolean struct.

枚举成员Enumeration members

枚举的成员是枚举中声明的常量和从枚举的直接基类继承的成员 System.Enum 和间接基类 System.ValueTypeobjectThe members of an enumeration are the constants declared in the enumeration and the members inherited from the enumeration's direct base class System.Enum and the indirect base classes System.ValueType and object.

类成员Class members

类的成员是在类中声明的成员和从基类继承的成员(没有基类的类 object 除外)。The members of a class are the members declared in the class and the members inherited from the base class (except for class object which has no base class). 从基类继承的成员包括常数、字段、方法、属性、事件、索引器、运算符和基类的类型,但不包括基类的实例构造函数、析构函数和静态构造函数。The members inherited from the base class include the constants, fields, methods, properties, events, indexers, operators, and types of the base class, but not the instance constructors, destructors and static constructors of the base class. 继承基类成员,而不考虑其可访问性。Base class members are inherited without regard to their accessibility.

类声明可以包含常量、字段、方法、属性、事件、索引器、运算符、实例构造函数、析构函数、静态构造函数和类型的声明。A class declaration may contain declarations of constants, fields, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors and types.

@No__t 和 @no__t 1 的成员直接对应于其别名的类类型的成员:The members of object and string correspond directly to the members of the class types they alias:

  • @No__t 的成员是 @no__t 类的成员。The members of object are the members of the System.Object class.
  • @No__t 的成员是 @no__t 类的成员。The members of string are the members of the System.String class.

接口成员Interface members

接口的成员是在接口和接口的所有基接口中声明的成员。The members of an interface are the members declared in the interface and in all base interfaces of the interface. object 中的成员并不严格地说是任何接口(接口成员)的成员。The members in class object are not, strictly speaking, members of any interface (Interface members). 但是,可以通过成员查找在任何接口类型中(成员查找)使用类 object 中的成员。However, the members in class object are available via member lookup in any interface type (Member lookup).

数组成员Array members

数组成员是从类 System.Array 继承的成员。The members of an array are the members inherited from class System.Array.

委托成员Delegate members

委托的成员是从类 System.Delegate 继承的成员。The members of a delegate are the members inherited from class System.Delegate.

成员访问Member access

成员的声明允许控制成员访问。Declarations of members allow control over member access. 成员的可访问性是由成员的声明的可访问性(已声明可访问性)建立的,该成员与直接包含类型的可访问性(如果有)结合使用。The accessibility of a member is established by the declared accessibility (Declared accessibility) of the member combined with the accessibility of the immediately containing type, if any.

如果允许访问特定成员,则认为该成员是可访问的。When access to a particular member is allowed, the member is said to be accessible. 相反,当不允许访问特定成员时,该成员被称为不可访问。Conversely, when access to a particular member is disallowed, the member is said to be inaccessible. 如果访问发生的文本位置包含在成员的可访问域(可访问域)中,则允许访问成员。Access to a member is permitted when the textual location in which the access takes place is included in the accessibility domain (Accessibility domains) of the member.

声明的可访问性Declared accessibility

成员的声明可访问性可以是以下项之一:The declared accessibility of a member can be one of the following:

  • 公共,通过在成员声明中包含 public 修饰符来选择。Public, which is selected by including a public modifier in the member declaration. @No__t-0 的直观含义为 "访问不受限制"。The intuitive meaning of public is "access not limited".
  • Protected:通过在成员声明中包含 protected 修饰符来选择。Protected, which is selected by including a protected modifier in the member declaration. @No__t-0 的直观含义为 "访问包含类或派生自包含类的类型"。The intuitive meaning of protected is "access limited to the containing class or types derived from the containing class".
  • 内部,通过在成员声明中包含 internal 修饰符来选择。Internal, which is selected by including an internal modifier in the member declaration. @No__t-0 的直观含义为 "访问此程序受限"。The intuitive meaning of internal is "access limited to this program".
  • 受保护的内部(这是受保护的或内部的),通过在成员声明中包括 @no__t 0 和 @no__t 修饰符来选择。Protected internal (meaning protected or internal), which is selected by including both a protected and an internal modifier in the member declaration. @No__t-0 的直观含义为 "访问此程序或派生自包含类的类型"。The intuitive meaning of protected internal is "access limited to this program or types derived from the containing class".
  • Private,通过在成员声明中包含 private 修饰符来选择。Private, which is selected by including a private modifier in the member declaration. @No__t-0 的直观含义为 "访问包含类型"。The intuitive meaning of private is "access limited to the containing type".

根据成员声明发生的上下文,仅允许某些类型的声明的可访问性。Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. 此外,当成员声明中不包含任何访问修饰符时,在其中进行声明的上下文会确定默认的声明的可访问性。Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility.

  • 命名空间隐式具有 @no__t 的可访问性。Namespaces implicitly have public declared accessibility. 命名空间声明中不允许使用访问修饰符。No access modifiers are allowed on namespace declarations.
  • 在编译单元或命名空间中声明的类型可以有 public 或 @no__t 1 声明的可访问性,并且默认为 internal 声明的可访问性。Types declared in compilation units or namespaces can have public or internal declared accessibility and default to internal declared accessibility.
  • 类成员可以具有五种声明的可访问性,并且默认为 private 声明的可访问性。Class members can have any of the five kinds of declared accessibility and default to private declared accessibility. (请注意,声明为类成员的类型可以具有五种声明可访问性中的任何一种,而声明为命名空间成员的类型只能有 public 或 @no__t 1 声明的可访问性。)(Note that a type declared as a member of a class can have any of the five kinds of declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility.)
  • 结构成员可以有 publicinternal 或 @no__t 声明的可访问性和默认值 @no__t,因为结构是隐式密封的。Struct members can have public, internal, or private declared accessibility and default to private declared accessibility because structs are implicitly sealed. 结构中引入的结构成员(即,不是由该结构继承)不能有 protected 或 @no__t 声明的可访问性。Struct members introduced in a struct (that is, not inherited by that struct) cannot have protected or protected internal declared accessibility. (请注意,声明为结构成员的类型可以有 publicinternal 或 @no__t 声明的可访问性,而声明为命名空间成员的类型只能具有 public 或 @no__t 的可访问性。)(Note that a type declared as a member of a struct can have public, internal, or private declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility.)
  • 接口成员隐式具有 @no__t 的可访问性。Interface members implicitly have public declared accessibility. 接口成员声明中不允许使用访问修饰符。No access modifiers are allowed on interface member declarations.
  • 枚举成员隐式具有 @no__t 的可访问性。Enumeration members implicitly have public declared accessibility. 枚举成员声明中不允许使用访问修饰符。No access modifiers are allowed on enumeration member declarations.

辅助功能域Accessibility domains

成员的可访问域包含允许访问成员的程序文本(可能不连续)部分。The accessibility domain of a member consists of the (possibly disjoint) sections of program text in which access to the member is permitted. 出于定义成员的可访问性域的目的,如果成员未在类型内声明,则称为顶级成员,如果在另一种类型中声明成员,则称嵌套成员。For purposes of defining the accessibility domain of a member, a member is said to be top-level if it is not declared within a type, and a member is said to be nested if it is declared within another type. 此外,程序的程序文本定义为程序的所有源文件中包含的所有程序文本,类型的程序文本定义为该类型的type_declaration中包含的所有程序文本(包括、可能是嵌套在类型中的类型)。Furthermore, the program text of a program is defined as all program text contained in all source files of the program, and the program text of a type is defined as all program text contained in the type_declarations of that type (including, possibly, types that are nested within the type).

预定义类型的可访问域(例如 objectintdouble)不受限制。The accessibility domain of a predefined type (such as object, int, or double) is unlimited.

在程序 P 中声明的顶级未绑定类型 @no__t 的可访问域(绑定类型和未绑定类型)的定义如下:The accessibility domain of a top-level unbound type T (Bound and unbound types) that is declared in a program P is defined as follows:

  • 如果 T 的声明的可访问性 @no__t 为-1,@no__t 的可访问域就是 @no__t 3 的程序文本和引用 P 的任何程序。If the declared accessibility of T is public, the accessibility domain of T is the program text of P and any program that references P.
  • 如果 T 的已声明可访问性为 internal,则 T 的可访问域就是 P 的程序文本。If the declared accessibility of T is internal, the accessibility domain of T is the program text of P.

从这些定义开始,顶级未绑定类型的可访问域始终至少是声明该类型的程序的程序文本。From these definitions it follows that the accessibility domain of a top-level unbound type is always at least the program text of the program in which that type is declared.

构造类型 T<A1, ..., An> 的可访问性域是未绑定的泛型类型的可访问域的交集 T 和类型参数 A1, ..., An 的可访问性域的交集。The accessibility domain for a constructed type T<A1, ..., An> is the intersection of the accessibility domain of the unbound generic type T and the accessibility domains of the type arguments A1, ..., An.

在程序 P 中声明的类型 T 中声明的嵌套成员 M 的可访问域定义如下(请注意,@no__t 本身可能是一个类型):The accessibility domain of a nested member M declared in a type T within a program P is defined as follows (noting that M itself may possibly be a type):

  • 如果 M 的已声明可访问性为 public,则 M 的可访问域就是 T 的可访问域。If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.
  • 如果 M 的声明的可访问性 @no__t 为-1,则允许 D 作为从 @no__t 到 @no__t 之外声明的任何类型的程序 @no__t 文本的联合,该程序文本与If the declared accessibility of M is protected internal, let D be the union of the program text of P and the program text of any type derived from T, which is declared outside P. @No__t 的可访问域是 @no__t 的可访问域与 D 的交集。The accessibility domain of M is the intersection of the accessibility domain of T with D.
  • 如果 M 的声明的可访问性 @no__t 为-1,则允许 D 作为 @no__t 3 的程序文本和从 @no__t 派生的任何类型的程序文本的联合。If the declared accessibility of M is protected, let D be the union of the program text of T and the program text of any type derived from T. @No__t 的可访问域是 @no__t 的可访问域与 D 的交集。The accessibility domain of M is the intersection of the accessibility domain of T with D.
  • 如果 M 的已声明可访问性为 internal,则 M 的可访问域就是 T 的可访问域与 P 的程序文本之间的交集。If the declared accessibility of M is internal, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of P.
  • 如果 M 的已声明可访问性为 private,则 M 的可访问域就是 T 的程序文本。If the declared accessibility of M is private, the accessibility domain of M is the program text of T.

从这些定义开始,嵌套成员的可访问域始终至少是声明该成员的类型的程序文本。From these definitions it follows that the accessibility domain of a nested member is always at least the program text of the type in which the member is declared. 此外,它还会将成员的可访问域与声明该成员的类型的可访问性域完全相同。Furthermore, it follows that the accessibility domain of a member is never more inclusive than the accessibility domain of the type in which the member is declared.

直观地说,当访问一个类型或成员 M 时,将评估以下步骤以确保允许访问:In intuitive terms, when a type or member M is accessed, the following steps are evaluated to ensure that the access is permitted:

  • 首先,如果在类型(而不是编译单元或命名空间)中声明 M,则当该类型不可访问时,将发生编译时错误。First, if M is declared within a type (as opposed to a compilation unit or a namespace), a compile-time error occurs if that type is not accessible.
  • 如果 M @no__t 为-1,则允许访问。Then, if M is public, the access is permitted.
  • 否则,如果 M @no__t 为-1,则允许访问,如果它出现在声明了 M 的程序中,或出现在派生自类的类 @no__t 中,并且该类是通过派生类类型进行的(受保护实例成员的访问权限)。Otherwise, if M is protected internal, the access is permitted if it occurs within the program in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (Protected access for instance members).
  • 否则,如果 M @no__t 为-1,则允许访问,如果它出现在声明了 M 的类中,或者出现在派生自 @no__t 类的类中,而该类是通过派生类类型(受保护实例成员的访问权限)。Otherwise, if M is protected, the access is permitted if it occurs within the class in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (Protected access for instance members).
  • 否则,如果 M @no__t 为-1,则允许访问,如果在声明 M 的程序中发生。Otherwise, if M is internal, the access is permitted if it occurs within the program in which M is declared.
  • 否则,如果 M @no__t 为-1,则允许访问,如果在声明 M 的类型内发生。Otherwise, if M is private, the access is permitted if it occurs within the type in which M is declared.
  • 否则,将无法访问该类型或成员,并发生编译时错误。Otherwise, the type or member is inaccessible, and a compile-time error occurs.

示例中In the example

public class A
{
    public static int X;
    internal static int Y;
    private static int Z;
}

internal class B
{
    public static int X;
    internal static int Y;
    private static int Z;

    public class C
    {
        public static int X;
        internal static int Y;
        private static int Z;
    }

    private class D
    {
        public static int X;
        internal static int Y;
        private static int Z;
    }
}

类和成员具有以下可访问域:the classes and members have the following accessibility domains:

  • @No__t 的可访问性域(0)和 A.X 无限制。The accessibility domain of A and A.X is unlimited.
  • @No__t 的可访问域,BB.XB.YB.CB.C.XB.C.Y 是包含程序的程序文本。The accessibility domain of A.Y, B, B.X, B.Y, B.C, B.C.X, and B.C.Y is the program text of the containing program.
  • @No__t 的可访问域是 @no__t 的程序文本。The accessibility domain of A.Z is the program text of A.
  • @No__t 的可访问性域(0)和 B.DB 的程序文本,包括 B.C 和 @no__t 的程序文本。The accessibility domain of B.Z and B.D is the program text of B, including the program text of B.C and B.D.
  • @No__t 的可访问域是 @no__t 的程序文本。The accessibility domain of B.C.Z is the program text of B.C.
  • @No__t 的可访问性域(0)和 B.D.YB 的程序文本,包括 B.C 和 @no__t 的程序文本。The accessibility domain of B.D.X and B.D.Y is the program text of B, including the program text of B.C and B.D.
  • @No__t 的可访问域是 @no__t 的程序文本。The accessibility domain of B.D.Z is the program text of B.D.

如示例所示,成员的可访问域绝不会超出包含类型的可访问域。As the example illustrates, the accessibility domain of a member is never larger than that of a containing type. 例如,即使所有 @no__t 0 的成员都具有公开声明的可访问性,但所有 A.X 都包含受包含类型约束的可访问域。For example, even though all X members have public declared accessibility, all but A.X have accessibility domains that are constrained by a containing type.

成员中所述,基类的所有成员(实例构造函数、析构函数和静态构造函数除外)都是由派生类型继承的。As described in Members, all members of a base class, except for instance constructors, destructors and static constructors, are inherited by derived types. 这包括甚至是基类的私有成员。This includes even private members of a base class. 但是,私有成员的可访问域只包含声明该成员的类型的程序文本。However, the accessibility domain of a private member includes only the program text of the type in which the member is declared. 示例中In the example

class A
{
    int x;

    static void F(B b) {
        b.x = 1;        // Ok
    }
}

class B: A
{
    static void F(B b) {
        b.x = 1;        // Error, x not accessible
    }
}

B 类从 A 类继承私有成员 @no__t。the B class inherits the private member x from the A class. 由于此成员是私有的,因此只能在 Aclass_body内访问。Because the member is private, it is only accessible within the class_body of A. 因此,对 @no__t 0 的访问成功于 A.F 方法中,但在 B.F 方法中失败。Thus, the access to b.x succeeds in the A.F method, but fails in the B.F method.

实例成员的受保护访问Protected access for instance members

如果在声明 @no__t 0 实例成员的类的程序文本的外部访问该成员,并且在声明该成员的程序的程序文本的外部访问 @no__t 1 实例成员,则必须在类中进行访问派生自其声明类的声明。When a protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access must take place within a class declaration that derives from the class in which it is declared. 此外,需要通过派生类类型的实例或从其构造的类类型进行访问。Furthermore, the access is required to take place through an instance of that derived class type or a class type constructed from it. 此限制可防止一个派生类访问其他派生类的受保护成员,即使这些成员是从同一个基类继承时也是如此。This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.

让 @no__t 是一个基类,该基类声明受保护的实例成员 M,并让 D 是派生自 @no__t 的类。Let B be a base class that declares a protected instance member M, and let D be a class that derives from B. Dclass_body中,对 @no__t 的访问可以采用以下形式之一:Within the class_body of D, access to M can take one of the following forms:

  • 格式 @no__t 的非限定的type_nameprimary_expressionAn unqualified type_name or primary_expression of the form M.
  • 如果 E 的类型为 T 或从 T 派生的类,则为形式 E.Mprimary_expression ,其中 T 是类类型 D,或是从 @no__t 构造的类类型A primary_expression of the form E.M, provided the type of E is T or a class derived from T, where T is the class type D, or a class type constructed from D
  • 形式 base.Mprimary_expressionA primary_expression of the form base.M.

除这些形式的访问权限外,派生类还可以访问constructor_initializer中的基类的受保护实例构造函数(构造函数初始值设定项)。In addition to these forms of access, a derived class can access a protected instance constructor of a base class in a constructor_initializer (Constructor initializers).

示例中In the example

public class A
{
    protected int x;

    static void F(A a, B b) {
        a.x = 1;        // Ok
        b.x = 1;        // Ok
    }
}

public class B: A
{
    static void F(A a, B b) {
        a.x = 1;        // Error, must access through instance of B
        b.x = 1;        // Ok
    }
}

A 中,可以通过 @no__t 2 和 B 的实例访问 @no__t 1,因为在这两种情况下,都可以通过 @no__t 的实例进行访问,或从 @no__t 5 派生的类进行访问。within A, it is possible to access x through instances of both A and B, since in either case the access takes place through an instance of A or a class derived from A. 但是,在 B 中,无法通过 A 的实例访问 @no__t,因为 A 不从 @no__t 派生。However, within B, it is not possible to access x through an instance of A, since A does not derive from B.

示例中In the example

class C<T>
{
    protected T x;
}

class D<T>: C<T>
{
    static void F() {
        D<T> dt = new D<T>();
        D<int> di = new D<int>();
        D<string> ds = new D<string>();
        dt.x = default(T);
        di.x = 123;
        ds.x = "test";
    }
}

允许对 @no__t 的三个赋值,因为它们都是通过从泛型类型构造的类类型的实例进行的。the three assignments to x are permitted because they all take place through instances of class types constructed from the generic type.

辅助功能约束Accessibility constraints

语言中的C#几个构造要求类型必须至少具有与成员或其他类型一样的可访问性Several constructs in the C# language require a type to be at least as accessible as a member or another type. 如果 T 的可访问域是 M 的可访问域的超集,则将类型 T 称为至少可作为成员或类型进行访问 MA type T is said to be at least as accessible as a member or type M if the accessibility domain of T is a superset of the accessibility domain of M. 换言之,如果 @no__t 可访问的所有 @no__t 上下文中都可访问-2,则 T 至少可作为 M 可访问。In other words, T is at least as accessible as M if T is accessible in all contexts in which M is accessible.

存在以下可访问性约束:The following accessibility constraints exist:

  • 类类型的直接基类必须至少具有与类类型本身相同的可访问性。The direct base class of a class type must be at least as accessible as the class type itself.
  • 接口类型的显式基接口必须至少具有与接口类型本身相同的可访问性。The explicit base interfaces of an interface type must be at least as accessible as the interface type itself.
  • 委托类型的返回类型和参数类型必须至少具有与委托类型本身相同的可访问性。The return type and parameter types of a delegate type must be at least as accessible as the delegate type itself.
  • 常量的类型必须至少具有与常量本身相同的可访问性。The type of a constant must be at least as accessible as the constant itself.
  • 字段的类型必须至少具有与字段本身相同的可访问性。The type of a field must be at least as accessible as the field itself.
  • 方法的返回类型和参数类型必须至少具有与方法本身相同的可访问性。The return type and parameter types of a method must be at least as accessible as the method itself.
  • 属性的类型必须至少具有与属性本身相同的可访问性。The type of a property must be at least as accessible as the property itself.
  • 事件的类型必须至少具有与事件本身相同的可访问性。The type of an event must be at least as accessible as the event itself.
  • 索引器的类型和参数类型必须至少具有与索引器本身相同的可访问性。The type and parameter types of an indexer must be at least as accessible as the indexer itself.
  • 运算符的类型和参数类型必须至少具有与运算符本身相同的可访问性。The return type and parameter types of an operator must be at least as accessible as the operator itself.
  • 实例构造函数的参数类型必须至少具有与实例构造函数本身相同的可访问性。The parameter types of an instance constructor must be at least as accessible as the instance constructor itself.

示例中In the example

class A {...}

public class B: A {...}

B 类会导致编译时错误,因为 A 至少不能作为 B 的访问。the B class results in a compile-time error because A is not at least as accessible as B.

同样,在示例中Likewise, in the example

class A {...}

public class B
{
    A F() {...}

    internal A G() {...}

    public A H() {...}
}

B 中的 H 方法导致编译时错误,因为 A 的返回类型并不至少与方法相同。the H method in B results in a compile-time error because the return type A is not at least as accessible as the method.

签名和重载Signatures and overloading

方法、实例构造函数、索引器和运算符按其签名特征:Methods, instance constructors, indexers, and operators are characterized by their signatures:

  • 方法的签名由方法的名称、类型参数的数目以及其每个形参的类型和种类(值、引用或输出)组成,按从左到右的顺序排列。The signature of a method consists of the name of the method, the number of type parameters and the type and kind (value, reference, or output) of each of its formal parameters, considered in the order left to right. 出于这些目的,形参的类型中出现的方法的任何类型形参均由其名称标识,但其在方法的类型实参列表中的序号位置。For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type argument list of the method. 具体而言,方法的签名不包括返回类型、可为最右侧参数指定的 params 修饰符和可选的类型参数约束。The signature of a method specifically does not include the return type, the params modifier that may be specified for the right-most parameter, nor the optional type parameter constraints.
  • 实例构造函数的签名由其每个形参的类型和类型(值、引用或输出)组成,按从左到右的顺序排列。The signature of an instance constructor consists of the type and kind (value, reference, or output) of each of its formal parameters, considered in the order left to right. 实例构造函数的签名具体不包括可以为最右侧参数指定的 params 修饰符。The signature of an instance constructor specifically does not include the params modifier that may be specified for the right-most parameter.
  • 索引器的签名由其每个形参的类型组成,按从左到右的顺序排列。The signature of an indexer consists of the type of each of its formal parameters, considered in the order left to right. 索引器的签名具体不包括元素类型,也不包括可以为最右侧参数指定的 params 修饰符。The signature of an indexer specifically does not include the element type, nor does it include the params modifier that may be specified for the right-most parameter.
  • 运算符的签名由运算符的名称和它的每个形参的类型组成,按从左到右的顺序排列。The signature of an operator consists of the name of the operator and the type of each of its formal parameters, considered in the order left to right. 运算符的签名具体不包括结果类型。The signature of an operator specifically does not include the result type.

签名是用于在类、结构和接口中重载成员的启用机制:Signatures are the enabling mechanism for overloading of members in classes, structs, and interfaces:

  • 方法的重载允许类、结构或接口声明多个具有相同名称的方法,前提是它们的签名在该类、结构或接口中是唯一的。Overloading of methods permits a class, struct, or interface to declare multiple methods with the same name, provided their signatures are unique within that class, struct, or interface.
  • 实例构造函数的重载允许类或结构声明多个实例构造函数,前提是它们的签名在该类或结构中是唯一的。Overloading of instance constructors permits a class or struct to declare multiple instance constructors, provided their signatures are unique within that class or struct.
  • 索引器的重载允许类、结构或接口声明多个索引器,前提是这些索引器的签名在该类、结构或接口中是唯一的。Overloading of indexers permits a class, struct, or interface to declare multiple indexers, provided their signatures are unique within that class, struct, or interface.
  • 运算符的重载允许类或结构声明多个具有相同名称的运算符,前提是它们的签名在该类或结构中是唯一的。Overloading of operators permits a class or struct to declare multiple operators with the same name, provided their signatures are unique within that class or struct.

尽管 @no__t 0 和 @no__t 1 参数修饰符被视为签名的一部分,但在单个类型中声明的成员不能仅由 refout 中的签名有所不同。Although out and ref parameter modifiers are considered part of a signature, members declared in a single type cannot differ in signature solely by ref and out. 如果两个成员在同一类型中声明,但如果两个 @no__t 方法中的所有参数都已更改为 ref 修饰符,则会发生编译时错误。A compile-time error occurs if two members are declared in the same type with signatures that would be the same if all parameters in both methods with out modifiers were changed to ref modifiers. 对于签名匹配的其他目的(例如,隐藏或重写),refout 将被视为签名的一部分,并且彼此之间不匹配。For other purposes of signature matching (e.g., hiding or overriding), ref and out are considered part of the signature and do not match each other. (这一限制是为了C#使程序可以轻松地翻译为在公共语言基础结构(CLI)上运行,而不提供一种方法来定义仅在 refout 中存在差异的方法。)(This restriction is to allow C#  programs to be easily translated to run on the Common Language Infrastructure (CLI), which does not provide a way to define methods that differ solely in ref and out.)

对于签名,类型 objectdynamic 被视为相同。For the purposes of signatures, the types object and dynamic are considered the same. 因此,在单个类型中声明的成员可以不区分签名,而只是 objectdynamicMembers declared in a single type can therefore not differ in signature solely by object and dynamic.

下面的示例演示一组重载方法声明及其签名。The following example shows a set of overloaded method declarations along with their signatures.

interface ITest
{
    void F();                        // F()

    void F(int x);                   // F(int)

    void F(ref int x);               // F(ref int)

    void F(out int x);               // F(out int)      error

    void F(int x, int y);            // F(int, int)

    int F(string s);                 // F(string)

    int F(int x);                    // F(int)          error

    void F(string[] a);              // F(string[])

    void F(params string[] a);       // F(string[])     error
}

请注意,任何 @no__t 0 和 @no__t 参数修饰符(方法参数)都是签名的一部分。Note that any ref and out parameter modifiers (Method parameters) are part of a signature. 因此,@no__t 0 和 @no__t 为唯一的签名。Thus, F(int) and F(ref int) are unique signatures. 但是,不能在同一接口内声明 F(ref int)F(out int),因为它们的签名仅因 ref 和 @no__t 而有所不同。However, F(ref int) and F(out int) cannot be declared within the same interface because their signatures differ solely by ref and out. 另请注意,返回类型和 params 修饰符不是签名的一部分,因此不可能仅基于返回类型或在包含或排除 @no__t 修饰符时重载。Also, note that the return type and the params modifier are not part of a signature, so it is not possible to overload solely based on return type or on the inclusion or exclusion of the params modifier. 同样,在上面标识的方法的声明 F(int) 和 @no__t 1 会导致编译时错误。As such, the declarations of the methods F(int) and F(params string[]) identified above result in a compile-time error.

范围Scopes

名称的作用域是程序文本的区域,在该区域中,可以引用名称声明的实体,而无需限定名称。The scope of a name is the region of program text within which it is possible to refer to the entity declared by the name without qualification of the name. 可以嵌套作用域,内部作用域可以从外部作用域中重新声明名称的含义(但这并不能删除嵌套块中的声明施加的限制,不能使用与封闭块中的本地变量相同的名称)。Scopes can be nested, and an inner scope may redeclare the meaning of a name from an outer scope (this does not, however, remove the restriction imposed by Declarations that within a nested block it is not possible to declare a local variable with the same name as a local variable in an enclosing block). 然后,在内部范围所涵盖的程序文本区域中隐藏外部范围的名称,并且只能通过限定名称来访问外部名称。The name from the outer scope is then said to be hidden in the region of program text covered by the inner scope, and access to the outer name is only possible by qualifying the name.

  • Namespace_member_declaration命名空间成员)声明的命名空间成员的作用域不包含任何封闭namespace_declaration ,是整个程序文本。The scope of a namespace member declared by a namespace_member_declaration (Namespace members) with no enclosing namespace_declaration is the entire program text.
  • Namespace_declarationnamespace_member_declaration声明的命名空间成员的作用域,其完全限定名称为 N 是每个namespace_declarationnamespace_body ,其完全限定名称为限定名 N 或以 N 开始,后跟一个句点。The scope of a namespace member declared by a namespace_member_declaration within a namespace_declaration whose fully qualified name is N is the namespace_body of every namespace_declaration whose fully qualified name is N or starts with N, followed by a period.
  • extern_alias_directive定义的名称的作用域超出其立即包含编译单元或命名空间正文的using_directives、 global_attributesnamespace_member_declarationThe scope of name defined by an extern_alias_directive extends over the using_directives, global_attributes and namespace_member_declarations of its immediately containing compilation unit or namespace body. Extern_alias_directive不会将任何新成员分配给基础声明空间。An extern_alias_directive does not contribute any new members to the underlying declaration space. 换句话说, extern_alias_directive是不可传递的,而是仅影响其出现在其中的编译单元或命名空间正文。In other words, an extern_alias_directive is not transitive, but, rather, affects only the compilation unit or namespace body in which it occurs.
  • Using_directive使用指令)定义或导入的名称的作用域扩展到compilation_unitnamespace_bodynamespace_member_declaration,其中using_directive发生。The scope of a name defined or imported by a using_directive (Using directives) extends over the namespace_member_declarations of the compilation_unit or namespace_body in which the using_directive occurs. Using_directive可以使特定compilation_unitnamespace_body中的零个或多个命名空间、类型或成员名称可用,但不会将任何新成员分配给基础声明空间。A using_directive may make zero or more namespace, type or member names available within a particular compilation_unit or namespace_body, but does not contribute any new members to the underlying declaration space. 换句话说, using_directive是不可传递的,而只会影响发生它的compilation_unitnamespace_bodyIn other words, a using_directive is not transitive but rather affects only the compilation_unit or namespace_body in which it occurs.
  • class_declaration上的type_parameter_list声明的类型参数的作用域(类声明)是该的class_basetype_parameter_constraints_clauseclass_bodyclass_declarationThe scope of a type parameter declared by a type_parameter_list on a class_declaration (Class declarations) is the class_base, type_parameter_constraints_clauses, and class_body of that class_declaration.
  • struct_declaration上的type_parameter_list声明的类型参数的作用域(结构声明)是的struct_interfacestype_parameter_constraints_clausestruct_bodystruct_declarationThe scope of a type parameter declared by a type_parameter_list on a struct_declaration (Struct declarations) is the struct_interfaces, type_parameter_constraints_clauses, and struct_body of that struct_declaration.
  • interface_declaration上的type_parameter_list声明的类型参数的作用域(接口声明)为interface_basetype_parameter_constraints_clauseinterface_bodyinterface_declarationThe scope of a type parameter declared by a type_parameter_list on an interface_declaration (Interface declarations) is the interface_base, type_parameter_constraints_clauses, and interface_body of that interface_declaration.
  • delegate_declaration上的type_parameter_list声明的类型参数的作用域(委托声明)为return_typeformal_parameter_listtype_parameter_constraints_clausedelegate_declarationThe scope of a type parameter declared by a type_parameter_list on a delegate_declaration (Delegate declarations) is the return_type, formal_parameter_list, and type_parameter_constraints_clauses of that delegate_declaration.
  • Class_member_declaration类体)声明的成员的作用域是在其中进行声明的class_bodyThe scope of a member declared by a class_member_declaration (Class body) is the class_body in which the declaration occurs. 此外,类成员的作用域扩展到包含在该成员的可访问域(可访问域)中的派生类的class_bodyIn addition, the scope of a class member extends to the class_body of those derived classes that are included in the accessibility domain (Accessibility domains) of the member.
  • Struct_member_declaration结构成员)声明的成员的作用域是在其中进行声明的struct_bodyThe scope of a member declared by a struct_member_declaration (Struct members) is the struct_body in which the declaration occurs.
  • Enum_member_declarationenum 成员)声明的成员的作用域是在其中进行声明的enum_bodyThe scope of a member declared by an enum_member_declaration (Enum members) is the enum_body in which the declaration occurs.
  • method_declaration方法)中声明的参数的作用域是该method_declarationmethod_bodyThe scope of a parameter declared in a method_declaration (Methods) is the method_body of that method_declaration.
  • indexer_declaration索引器)中声明的参数的作用域是该indexer_declarationaccessor_declarationsThe scope of a parameter declared in an indexer_declaration (Indexers) is the accessor_declarations of that indexer_declaration.
  • operator_declaration运算符)中声明的参数的作用域是该operator_declarationThe scope of a parameter declared in an operator_declaration (Operators) is the block of that operator_declaration.
  • constructor_declaration实例构造函数)中声明的参数的作用域是该constructor_declarationconstructor_initializerThe scope of a parameter declared in a constructor_declaration (Instance constructors) is the constructor_initializer and block of that constructor_declaration.
  • lambda_expression匿名函数表达式)中声明的参数的作用域是该lambda_expressionanonymous_function_bodyThe scope of a parameter declared in a lambda_expression (Anonymous function expressions) is the anonymous_function_body of that lambda_expression
  • anonymous_method_expression匿名函数表达式)中声明的参数的作用域是该anonymous_method_expressionThe scope of a parameter declared in an anonymous_method_expression (Anonymous function expressions) is the block of that anonymous_method_expression.
  • labeled_statement标记的语句)中声明的标签的作用域是在其中进行声明的The scope of a label declared in a labeled_statement (Labeled statements) is the block in which the declaration occurs.
  • local_variable_declaration局部变量声明)中声明的局部变量的作用域是在其中进行声明的块。The scope of a local variable declared in a local_variable_declaration (Local variable declarations) is the block in which the declaration occurs.
  • switch 语句(switch 语句)的switch_block中声明的局部变量的范围为switch_blockThe scope of a local variable declared in a switch_block of a switch statement (The switch statement) is the switch_block.
  • for 语句(for 语句)的for_initializer中声明的局部变量的作用域是for_initializerfor_conditionfor_iterator和包含的语句。@no__t 7 语句。The scope of a local variable declared in a for_initializer of a for statement (The for statement) is the for_initializer, the for_condition, the for_iterator, and the contained statement of the for statement.
  • local_constant_declaration中声明的局部常量的作用域(局部常量声明)是在其中进行声明的块。The scope of a local constant declared in a local_constant_declaration (Local constant declarations) is the block in which the declaration occurs. 在其constant_declarator之前的文本位置引用本地常量是编译时错误。It is a compile-time error to refer to a local constant in a textual position that precedes its constant_declarator.
  • 声明为foreach_statementusing_statementlock_statementquery_expression的一部分的变量的作用域由给定构造的扩展确定。The scope of a variable declared as part of a foreach_statement, using_statement, lock_statement or query_expression is determined by the expansion of the given construct.

在命名空间、类、结构或枚举成员的作用域内,可以引用成员声明之前的文本位置中的成员。Within the scope of a namespace, class, struct, or enumeration member it is possible to refer to the member in a textual position that precedes the declaration of the member. 例如For example

class A
{
    void F() {
        i = 1;
    }

    int i = 0;
}

此处,在声明之前,F 引用 @no__t。Here, it is valid for F to refer to i before it is declared.

在局部变量的作用域内,在本地变量的local_variable_declarator之前的文本位置引用本地变量是编译时错误。Within the scope of a local variable, it is a compile-time error to refer to the local variable in a textual position that precedes the local_variable_declarator of the local variable. 例如For example

class A
{
    int i = 0;

    void F() {
        i = 1;                  // Error, use precedes declaration
        int i;
        i = 2;
    }

    void G() {
        int j = (j = 1);        // Valid
    }

    void H() {
        int a = 1, b = ++a;    // Valid
    }
}

在上面的 F 方法中,第一次分配给 @no__t 的第1项并未引用在外部作用域中声明的字段。In the F method above, the first assignment to i specifically does not refer to the field declared in the outer scope. 相反,它是指局部变量,它会导致编译时错误,因为它在此变量的声明之前。Rather, it refers to the local variable and it results in a compile-time error because it textually precedes the declaration of the variable. G 方法中,在 j 的声明的初始值设定项中使用 @no__t 是有效的,因为使用不在local_variable_declarator之前。In the G method, the use of j in the initializer for the declaration of j is valid because the use does not precede the local_variable_declarator. H 方法中,后续local_variable_declarator正确引用在同一local_variable_declaration中的早期local_variable_declarator中声明的局部变量。In the H method, a subsequent local_variable_declarator correctly refers to a local variable declared in an earlier local_variable_declarator within the same local_variable_declaration.

局部变量的作用域规则旨在确保表达式上下文中使用的名称的含义在块中始终相同。The scoping rules for local variables are designed to guarantee that the meaning of a name used in an expression context is always the same within a block. 如果本地变量的作用域只是从其声明扩展到块的末尾,则第一个赋值将分配给实例变量,第二个赋值将分配给局部变量,这可能会导致编译时错误(如果以后要重新排列块的语句)。If the scope of a local variable were to extend only from its declaration to the end of the block, then in the example above, the first assignment would assign to the instance variable and the second assignment would assign to the local variable, possibly leading to compile-time errors if the statements of the block were later to be rearranged.

块内的名称含义可能因使用该名称的上下文而异。The meaning of a name within a block may differ based on the context in which the name is used. 示例中In the example

using System;

class A {}

class Test
{
    static void Main() {
        string A = "hello, world";
        string s = A;                            // expression context

        Type t = typeof(A);                      // type context

        Console.WriteLine(s);                    // writes "hello, world"
        Console.WriteLine(t);                    // writes "A"
    }
}

名称 A 用于在表达式上下文中引用局部变量 A 和在类型上下文中以引用类 Athe name A is used in an expression context to refer to the local variable A and in a type context to refer to the class A.

名称隐藏Name hiding

实体的作用域通常比实体的声明空间包含更多的程序文本。The scope of an entity typically encompasses more program text than the declaration space of the entity. 具体而言,实体的范围可能包括引入新声明空间的声明,这些声明空间包含具有相同名称的实体。In particular, the scope of an entity may include declarations that introduce new declaration spaces containing entities of the same name. 此类声明会使原始实体处于隐藏状态Such declarations cause the original entity to become hidden. 相反,如果实体未隐藏,则称该实体可见Conversely, an entity is said to be visible when it is not hidden.

如果范围通过嵌套重叠,并且作用域通过继承重叠,则会发生名称隐藏。Name hiding occurs when scopes overlap through nesting and when scopes overlap through inheritance. 以下各节将介绍这两种隐藏类型的特征。The characteristics of the two types of hiding are described in the following sections.

通过嵌套隐藏Hiding through nesting

由于嵌套命名空间或命名空间中的类型、类或结构中的嵌套类型以及参数和局部变量声明的结果,因此可以通过嵌套命名空间。Name hiding through nesting can occur as a result of nesting namespaces or types within namespaces, as a result of nesting types within classes or structs, and as a result of parameter and local variable declarations.

示例中In the example

class A
{
    int i = 0;

    void F() {
        int i = 1;
    }

    void G() {
        i = 1;
    }
}

F 方法中,实例变量 i 由局部变量 i 隐藏,但在 G 方法中,i 仍引用实例变量。within the F method, the instance variable i is hidden by the local variable i, but within the G method, i still refers to the instance variable.

当内部范围中的名称隐藏外部范围内的名称时,它将隐藏该名称的所有重载匹配项。When a name in an inner scope hides a name in an outer scope, it hides all overloaded occurrences of that name. 示例中In the example

class Outer
{
    static void F(int i) {}

    static void F(string s) {}

    class Inner
    {
        void G() {
            F(1);              // Invokes Outer.Inner.F
            F("Hello");        // Error
        }

        static void F(long l) {}
    }
}

调用 F(1) 会调用 Inner 中声明的 @no__t,因为内部声明隐藏了 @no__t 的所有外部匹配项。the call F(1) invokes the F declared in Inner because all outer occurrences of F are hidden by the inner declaration. 由于同样的原因,调用 F("Hello") 会导致编译时错误。For the same reason, the call F("Hello") results in a compile-time error.

通过继承隐藏Hiding through inheritance

当类或结构重新声明从基类继承的名称时,通过继承进行名称隐藏。Name hiding through inheritance occurs when classes or structs redeclare names that were inherited from base classes. 此类名称隐藏采用以下形式之一:This type of name hiding takes one of the following forms:

  • 类或结构中引入的常数、字段、属性、事件或类型隐藏了具有相同名称的所有基类成员。A constant, field, property, event, or type introduced in a class or struct hides all base class members with the same name.
  • 类或结构中引入的方法会隐藏所有具有相同名称的非方法基类成员,并隐藏具有相同签名的所有基类方法(方法名称和参数计数、修饰符和类型)。A method introduced in a class or struct hides all non-method base class members with the same name, and all base class methods with the same signature (method name and parameter count, modifiers, and types).
  • 类或结构中引入的索引器会隐藏具有相同签名的所有基类索引器(参数计数和类型)。An indexer introduced in a class or struct hides all base class indexers with the same signature (parameter count and types).

控制运算符声明(运算符)的规则使得派生类不可能使用与基类中的运算符相同的签名来声明运算符。The rules governing operator declarations (Operators) make it impossible for a derived class to declare an operator with the same signature as an operator in a base class. 因此,运算符永远不会彼此隐藏。Thus, operators never hide one another.

与隐藏外部作用域中的名称相反,从继承的作用域中隐藏可访问的名称会导致报告警告。Contrary to hiding a name from an outer scope, hiding an accessible name from an inherited scope causes a warning to be reported. 示例中In the example

class Base
{
    public void F() {}
}

class Derived: Base
{
    public void F() {}        // Warning, hiding an inherited name
}

Derived 中 @no__t 的声明会导致报告警告。the declaration of F in Derived causes a warning to be reported. 隐藏继承名称特别不是错误,因为这会阻止基类的单独演化。Hiding an inherited name is specifically not an error, since that would preclude separate evolution of base classes. 例如,上述情况可能已涉及,因为更高版本的 Base 引入了类的早期版本中不存在的 @no__t 1 方法。For example, the above situation might have come about because a later version of Base introduced an F method that wasn't present in an earlier version of the class. 如果上述情况是错误的,则对单独的版本控制类库中的基类进行的任何更改都可能导致派生类无效。Had the above situation been an error, then any change made to a base class in a separately versioned class library could potentially cause derived classes to become invalid.

通过使用 new 修饰符,可以消除通过隐藏继承名称导致的警告:The warning caused by hiding an inherited name can be eliminated through use of the new modifier:

class Base
{
    public void F() {}
}

class Derived: Base
{
    new public void F() {}
}

@No__t-0 修饰符指示 Derived 中的 @no__t 为 "new",它确实用于隐藏继承的成员。The new modifier indicates that the F in Derived is "new", and that it is indeed intended to hide the inherited member.

新成员的声明仅在新成员的范围内隐藏继承的成员。A declaration of a new member hides an inherited member only within the scope of the new member.

class Base
{
    public static void F() {}
}

class Derived: Base
{
    new private static void F() {}    // Hides Base.F in Derived only
}

class MoreDerived: Derived
{
    static void G() { F(); }          // Invokes Base.F
}

在上面的示例中,DerivedF 的声明隐藏了从 Base 继承的 F,但由于 @no__t 5 中的新 @no__t 有私有访问权限,因此它的作用域不会扩展到 MoreDerivedIn the example above, the declaration of F in Derived hides the F that was inherited from Base, but since the new F in Derived has private access, its scope does not extend to MoreDerived. 因此,MoreDerived.G 中的调用 F() 有效,将调用 Base.FThus, the call F() in MoreDerived.G is valid and will invoke Base.F.

命名空间和类型名称Namespace and type names

程序中的多个上下文需要指定namespace_nametype_name。 C#Several contexts in a C# program require a namespace_name or a type_name to be specified.

namespace_name
    : namespace_or_type_name
    ;

type_name
    : namespace_or_type_name
    ;

namespace_or_type_name
    : identifier type_argument_list?
    | namespace_or_type_name '.' identifier type_argument_list?
    | qualified_alias_member
    ;

Namespace_name是引用命名空间的namespace_or_type_nameA namespace_name is a namespace_or_type_name that refers to a namespace. 按照下面所述的解决方法, namespace_namenamespace_or_type_name必须引用命名空间,否则将发生编译时错误。Following resolution as described below, the namespace_or_type_name of a namespace_name must refer to a namespace, or otherwise a compile-time error occurs. Namespace_name中不能存在任何类型参数(类型参数)(类型只能有类型参数)。No type arguments (Type arguments) can be present in a namespace_name (only types can have type arguments).

Type_name是引用类型的namespace_or_type_nameA type_name is a namespace_or_type_name that refers to a type. 按照下面所述的解决方法, type_namenamespace_or_type_name必须引用类型,否则将发生编译时错误。Following resolution as described below, the namespace_or_type_name of a type_name must refer to a type, or otherwise a compile-time error occurs.

如果namespace_or_type_name是一个限定别名成员,则其含义如命名空间别名限定符中所述。If the namespace_or_type_name is a qualified-alias-member its meaning is as described in Namespace alias qualifiers. 否则, namespace_or_type_name具有四种形式之一:Otherwise, a namespace_or_type_name has one of four forms:

  • I
  • I<A1, ..., Ak>
  • N.I
  • N.I<A1, ..., Ak>

其中 I 是单个标识符,Nnamespace_or_type_name ,@no__t 为可选的type_argument_listwhere I is a single identifier, N is a namespace_or_type_name and <A1, ..., Ak> is an optional type_argument_list. 如果未指定type_argument_list ,请考虑 k 为零。When no type_argument_list is specified, consider k to be zero.

确定namespace_or_type_name的含义,如下所示:The meaning of a namespace_or_type_name is determined as follows:

  • 如果namespace_or_type_name的格式 @no__t 为-1 或格式为 I<A1, ..., Ak>If the namespace_or_type_name is of the form I or of the form I<A1, ..., Ak>:
    • 如果 @no__t 为零且namespace_or_type_name显示在泛型方法声明(方法)中,并且如果声明包含名称为 @ no__t 的类型参数(类型参数),则namespace_or_type_名称是指该类型参数。If K is zero and the namespace_or_type_name appears within a generic method declaration (Methods) and if that declaration includes a type parameter (Type parameters) with name I, then the namespace_or_type_name refers to that type parameter.
    • 否则,如果namespace_or_type_name出现在类型声明中,则对于每个实例类型 @ no__t (实例类型),从该类型声明的实例类型开始,并继续使用每个实例的实例类型。封闭类或结构声明(如果有):Otherwise, if the namespace_or_type_name appears within a type declaration, then for each instance type T (The instance type), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
      • 如果 @no__t 为零,而 @no__t 的声明包含名为 @ no__t 的 type 参数,则namespace_or_type_name将引用该类型参数。If K is zero and the declaration of T includes a type parameter with name I, then the namespace_or_type_name refers to that type parameter.
      • 否则,如果namespace_or_type_name出现在类型声明的主体中,T 或它的任何基类型包含名为 @ no__t-2 和 K @ no__t-4type 参数的嵌套可访问类型,则namespace_or_type_name是指用给定类型参数构造的类型。Otherwise, if the namespace_or_type_name appears within the body of the type declaration, and T or any of its base types contain a nested accessible type having name I and K type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments. 如果有多个这样的类型,则选择在派生程度较大的类型中声明的类型。If there is more than one such type, the type declared within the more derived type is selected. 请注意,在确定的含义时,将忽略非类型成员(常数、字段、方法、属性、索引器、运算符、实例构造函数、析构函数和静态构造函数)和具有不同数量的类型参数的类型成员。namespace_or_type_nameNote that non-type members (constants, fields, methods, properties, indexers, operators, instance constructors, destructors, and static constructors) and type members with a different number of type parameters are ignored when determining the meaning of the namespace_or_type_name.
    • 如果前面的步骤不成功,则对于每个命名空间 @ no__t,从namespace_or_type_name发生的命名空间开始,继续每个封闭命名空间(如果有),并以全局命名空间结束,以下在查找实体之前计算步骤:If the previous steps were unsuccessful then, for each namespace N, starting with the namespace in which the namespace_or_type_name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
      • 如果 @no__t 为零且 @no__t 为 @ no__t 中的命名空间的名称,则:If K is zero and I is the name of a namespace in N, then:
        • 如果发生namespace_or_type_name的位置由 N 的命名空间声明括起来,并且命名空间声明包含将名称 @ no 关联的extern_alias_directiveusing_alias_directive__t-4,具有命名空间或类型,则namespace_or_type_name不明确,并发生编译时错误。If the location where the namespace_or_type_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the namespace_or_type_name is ambiguous and a compile-time error occurs.
        • 否则, namespace_or_type_name引用 N 中名为 I 的命名空间。Otherwise, the namespace_or_type_name refers to the namespace named I in N.
      • 否则,如果 N 包含名为 @ no__t 的可访问类型和 K @ no__t-3type 参数,则:Otherwise, if N contains an accessible type having name I and K type parameters, then:
        • 如果 @no__t 为零,且namespace_or_type_name的位置由 N 的命名空间声明括起来,并且命名空间声明包含extern_alias_directiveusing_alias_directive ,则将名称 @ no__t 与命名空间或类型相关联,然后namespace_or_type_name是不明确的,并发生编译时错误。If K is zero and the location where the namespace_or_type_name occurs is enclosed by a namespace declaration for N and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with a namespace or type, then the namespace_or_type_name is ambiguous and a compile-time error occurs.
        • 否则, namespace_or_type_name将引用用给定类型参数构造的类型。Otherwise, the namespace_or_type_name refers to the type constructed with the given type arguments.
      • 否则,如果namespace_or_type_name发生的位置由 N 的命名空间声明括起来,则为; 否则为。Otherwise, if the location where the namespace_or_type_name occurs is enclosed by a namespace declaration for N:
        • 如果 @no__t 为零,命名空间声明包含extern_alias_directiveusing_alias_directive ,它将名称 @ no__t 与导入的命名空间或类型相关联,则namespace_or_type_name引用命名空间或类型。If K is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the name I with an imported namespace or type, then the namespace_or_type_name refers to that namespace or type.
        • 否则,如果由命名空间声明中的using_namespace_directives 和using_alias_directives 导入的命名空间和类型声明包含一个名称为 @ no__t 的可访问类型和 K @ no__t-4type参数,则namespace_or_type_name引用以给定类型参数构造的类型。Otherwise, if the namespaces and type declarations imported by the using_namespace_directives and using_alias_directives of the namespace declaration contain exactly one accessible type having name I and K type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments.
        • 否则,如果由命名空间声明的using_namespace_directives 和using_alias_directives 导入的命名空间和类型声明包含多个名称为 @ no__t 和 K @ no__t-4type 的可访问类型参数,则namespace_or_type_name是不明确的,并发生错误。Otherwise, if the namespaces and type declarations imported by the using_namespace_directives and using_alias_directives of the namespace declaration contain more than one accessible type having name I and K type parameters, then the namespace_or_type_name is ambiguous and an error occurs.
    • 否则, namespace_or_type_name是未定义的,并发生编译时错误。Otherwise, the namespace_or_type_name is undefined and a compile-time error occurs.
  • 否则, namespace_or_type_name的格式 @no__t 为-1 或格式为 N.I<A1, ..., Ak>Otherwise, the namespace_or_type_name is of the form N.I or of the form N.I<A1, ..., Ak>. @no__t 首先解析为namespace_or_type_nameN is first resolved as a namespace_or_type_name. 如果 @no__t 的解析失败,则会发生编译时错误。If the resolution of N is not successful, a compile-time error occurs. 否则,将按如下方式解析 N.IN.I<A1, ..., Ak>Otherwise, N.I or N.I<A1, ..., Ak> is resolved as follows:
    • 如果 @no__t 为零,N 表示命名空间,N 包含名称 @no__t 为3的嵌套命名空间,则namespace_or_type_name引用该嵌套命名空间。If K is zero and N refers to a namespace and N contains a nested namespace with name I, then the namespace_or_type_name refers to that nested namespace.
    • 否则,如果 N 引用命名空间,并且 @no__t 包含名称为 @ no__t 的可访问类型和 K @ 4type 参数,则namespace_or_type_name引用使用给定类型参数构造的类型。Otherwise, if N refers to a namespace and N contains an accessible type having name I and K type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments.
    • 否则,如果 N 引用(可能构造的)类或结构类型,N 或它的任何一个基类包含名称为 @ no__t 的嵌套可访问性类型和 @no__t @ 4type 参数,则namespace_or_type_name引用用给定的类型参数构造的类型。Otherwise, if N refers to a (possibly constructed) class or struct type and N or any of its base classes contain a nested accessible type having name I and K type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments. 如果有多个这样的类型,则选择在派生程度较大的类型中声明的类型。If there is more than one such type, the type declared within the more derived type is selected. 请注意,如果将 N.I 的含义确定为解析 @no__t 的基类规范,则 N 的直接基类被视为对象(基类)。Note that if the meaning of N.I is being determined as part of resolving the base class specification of N then the direct base class of N is considered to be object (Base classes).
    • 否则,@no__t 为无效的namespace_or_type_name,并发生编译时错误。Otherwise, N.I is an invalid namespace_or_type_name, and a compile-time error occurs.

仅当使用namespace_or_type_name时,才能引用静态类(静态类A namespace_or_type_name is permitted to reference a static class (Static classes) only if

  • Namespace_or_type_nameT.I 形式的namespace_or_type_name中的 T,或The namespace_or_type_name is the T in a namespace_or_type_name of the form T.I, or
  • Namespace_or_type_nametypeof_expression参数列表1)中格式为 typeof(T) 的 @no__t。The namespace_or_type_name is the T in a typeof_expression (Argument lists1) of the form typeof(T).

完全限定的名称Fully qualified names

每个命名空间和类型都有一个完全限定的名称,该名称唯一地标识命名空间或类型。Every namespace and type has a fully qualified name, which uniquely identifies the namespace or type amongst all others. 按如下方式确定命名空间或类型 N 的完全限定名:The fully qualified name of a namespace or type N is determined as follows:

  • 如果 N 是全局命名空间的成员,则其完全限定名称为 NIf N is a member of the global namespace, its fully qualified name is N.
  • 否则,其完全限定名称为 S.N,其中 S 是声明 N 的命名空间或类型的完全限定名称。Otherwise, its fully qualified name is S.N, where S is the fully qualified name of the namespace or type in which N is declared.

换句话说,@no__t 的完全限定名是从全局命名空间开始 @no__t 的标识符的完整层次结构路径。In other words, the fully qualified name of N is the complete hierarchical path of identifiers that lead to N, starting from the global namespace. 由于命名空间或类型的每个成员都必须具有唯一的名称,因此命名空间或类型的完全限定名称始终是唯一的。Because every member of a namespace or type must have a unique name, it follows that the fully qualified name of a namespace or type is always unique.

下面的示例显示了几个命名空间和类型声明及其关联的完全限定名称。The example below shows several namespace and type declarations along with their associated fully qualified names.

class A {}                // A

namespace X               // X
{
    class B               // X.B
    {
        class C {}        // X.B.C
    }

    namespace Y           // X.Y
    {
        class D {}        // X.Y.D
    }
}

namespace X.Y             // X.Y
{
    class E {}            // X.Y.E
}

自动内存管理Automatic memory management

C#采用自动内存管理,使开发人员无手动分配和释放由对象占用的内存。C# employs automatic memory management, which frees developers from manually allocating and freeing the memory occupied by objects. 自动内存管理策略是由垃圾回收器实现的。Automatic memory management policies are implemented by a garbage collector. 对象的内存管理生命周期如下所示:The memory management life cycle of an object is as follows:

  1. 创建对象时,将为其分配内存,运行构造函数,并将对象视为实时对象。When the object is created, memory is allocated for it, the constructor is run, and the object is considered live.
  2. 如果对象或它的任何部分不能通过任何可能的执行继续进行访问,而不是运行析构函数,则该对象被视为不再使用,并可用于销毁。If the object, or any part of it, cannot be accessed by any possible continuation of execution, other than the running of destructors, the object is considered no longer in use, and it becomes eligible for destruction. C#编译器和垃圾回收器可以选择对代码进行分析,以确定将来可能会使用哪些对对象的引用。The C# compiler and the garbage collector may choose to analyze code to determine which references to an object may be used in the future. 例如,如果作用域中的局部变量是唯一的对象引用,但在过程中从当前执行点到执行的任何可能的继续,则不会引用该局部变量,垃圾回收器可能(但不是需要)将对象视为不再使用。For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, the garbage collector may (but is not required to) treat the object as no longer in use.
  3. 对象符合析构条件后,在某些以后未指定的情况下,将运行该对象的析构函数(如果有)。Once the object is eligible for destruction, at some unspecified later time the destructor (Destructors) (if any) for the object is run. 正常情况下,对象的析构函数只运行一次,不过实现特定的 Api 可能会允许重写此行为。Under normal circumstances the destructor for the object is run once only, though implementation-specific APIs may allow this behavior to be overridden.
  4. 一旦运行某个对象的析构函数,如果该对象或它的任何部分不能通过任何可能的执行继续进行访问,包括运行析构函数,则该对象将被视为不可访问,并且该对象便可用于收集。Once the destructor for an object is run, if that object, or any part of it, cannot be accessed by any possible continuation of execution, including the running of destructors, the object is considered inaccessible and the object becomes eligible for collection.
  5. 最后,在对象变为符合集合条件后,垃圾回收器将释放与该对象关联的内存。Finally, at some time after the object becomes eligible for collection, the garbage collector frees the memory associated with that object.

垃圾回收器维护有关对象使用情况的信息,并使用此信息进行内存管理决策,如在内存中查找新创建的对象的位置、何时重新定位对象以及对象不再使用或无法访问。The garbage collector maintains information about object usage, and uses this information to make memory management decisions, such as where in memory to locate a newly created object, when to relocate an object, and when an object is no longer in use or inaccessible.

与其他假设存在垃圾回收器的语言一样, C#设计使垃圾回收器可以实现各种内存管理策略。Like other languages that assume the existence of a garbage collector, C# is designed so that the garbage collector may implement a wide range of memory management policies. 例如, C#不要求运行析构函数,或在对象符合条件时收集对象,或者在任何特定的线程上以任何特定的顺序运行析构函数。For instance, C# does not require that destructors be run or that objects be collected as soon as they are eligible, or that destructors be run in any particular order, or on any particular thread.

可以通过类上的静态方法控制垃圾回收器的行为,使其在一定程度上控制 System.GCThe behavior of the garbage collector can be controlled, to some degree, via static methods on the class System.GC. 此类可用于请求进行集合、运行(或不运行)等操作。This class can be used to request a collection to occur, destructors to be run (or not run), and so forth.

由于垃圾回收器允许广泛的纬度来决定何时收集对象和运行析构函数,因此一致的实现可能产生与下面的代码所示不同的输出。Since the garbage collector is allowed wide latitude in deciding when to collect objects and run destructors, a conforming implementation may produce output that differs from that shown by the following code. 程序The program

using System;

class A
{
    ~A() {
        Console.WriteLine("Destruct instance of A");
    }
}

class B
{
    object Ref;

    public B(object o) {
        Ref = o;
    }

    ~B() {
        Console.WriteLine("Destruct instance of B");
    }
}

class Test
{
    static void Main() {
        B b = new B(new A());
        b = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

创建类 @no__t 的实例,B 的实例。creates an instance of class A and an instance of class B. 如果为变量 b 赋值 null,则这些对象将可以进行垃圾回收,因为在此之后,任何用户编写的代码都无法访问它们。These objects become eligible for garbage collection when the variable b is assigned the value null, since after this time it is impossible for any user-written code to access them. 输出可以是The output could be either

Destruct instance of A
Destruct instance of B

or

Destruct instance of B
Destruct instance of A

因为该语言对对象的垃圾回收顺序没有约束。because the language imposes no constraints on the order in which objects are garbage collected.

在微妙的情况下,"符合析构条件" 和 "符合集合条件" 之间的区别非常重要。In subtle cases, the distinction between "eligible for destruction" and "eligible for collection" can be important. 例如,应用于对象的For example,

using System;

class A
{
    ~A() {
        Console.WriteLine("Destruct instance of A");
    }

    public void F() {
        Console.WriteLine("A.F");
        Test.RefA = this;
    }
}

class B
{
    public A Ref;

    ~B() {
        Console.WriteLine("Destruct instance of B");
        Ref.F();
    }
}

class Test
{
    public static A RefA;
    public static B RefB;

    static void Main() {
        RefB = new B();
        RefA = new A();
        RefB.Ref = RefA;
        RefB = null;
        RefA = null;

        // A and B now eligible for destruction
        GC.Collect();
        GC.WaitForPendingFinalizers();

        // B now eligible for collection, but A is not
        if (RefA != null)
            Console.WriteLine("RefA is not null");
    }
}

在上述程序中,如果垃圾回收器选择在 B 的析构函数之前运行 A 的析构函数,则该程序的输出可能是:In the above program, if the garbage collector chooses to run the destructor of A before the destructor of B, then the output of this program might be:

Destruct instance of A
Destruct instance of B
A.F
RefA is not null

请注意,尽管 @no__t 的实例未被使用,并且运行了 A 的析构函数,但仍有可能从另一个析构函数调用 A (在本例中为 F)的方法。Note that although the instance of A was not in use and A's destructor was run, it is still possible for methods of A (in this case, F) to be called from another destructor. 另外,请注意,运行析构函数可能会导致对象再次可从主线程序使用。Also, note that running of a destructor may cause an object to become usable from the mainline program again. 在这种情况下,运行 @no__t 0 的析构函数会导致先前未使用的 @no__t 实例变为可从实时引用 Test.RefAIn this case, the running of B's destructor caused an instance of A that was previously not in use to become accessible from the live reference Test.RefA. 调用 WaitForPendingFinalizers 后,B 的实例符合集合条件,但 @no__t 的实例不是,因为引用 @no__t 为3。After the call to WaitForPendingFinalizers, the instance of B is eligible for collection, but the instance of A is not, because of the reference Test.RefA.

为了避免混淆和意外行为,通常情况下,析构函数只对存储在其自身字段中的数据执行清理,而不对引用的对象或静态字段执行任何操作。To avoid confusion and unexpected behavior, it is generally a good idea for destructors to only perform cleanup on data stored in their object's own fields, and not to perform any actions on referenced objects or static fields.

使用析构函数的替代方法是让类实现 System.IDisposable 接口。An alternative to using destructors is to let a class implement the System.IDisposable interface. 这允许对象的客户端确定何时释放对象的资源,这通常是通过在 using 语句(using 语句)中以资源的形式访问对象的。This allows the client of the object to determine when to release the resources of the object, typically by accessing the object as a resource in a using statement (The using statement).

执行顺序Execution order

C#程序的执行将继续,使每个正在执行的线程的副作用被保留在关键执行点上。Execution of a C# program proceeds such that the side effects of each executing thread are preserved at critical execution points. 副作用定义为可变字段的读取或写入、对非易失性变量的写入、写入外部资源和引发异常。A side effect is defined as a read or write of a volatile field, a write to a non-volatile variable, a write to an external resource, and the throwing of an exception. 必须保留这些副作用的顺序的关键执行点是对可变字段的引用(可变字段)、lock 语句(lock 语句)以及线程创建和终止。The critical execution points at which the order of these side effects must be preserved are references to volatile fields (Volatile fields), lock statements (The lock statement), and thread creation and termination. 执行环境可随意更改C#程序的执行顺序,但要服从以下限制:The execution environment is free to change the order of execution of a C# program, subject to the following constraints:

  • 数据依赖关系在执行线程中保留。Data dependence is preserved within a thread of execution. 也就是说,将计算每个变量的值,就好像该线程中的所有语句都是按原程序顺序执行的一样。That is, the value of each variable is computed as if all statements in the thread were executed in original program order.
  • 保留初始化排序规则(字段初始化变量初始值设定项)。Initialization ordering rules are preserved (Field initialization and Variable initializers).
  • 对于易失读写(可变字段),会保留副作用的顺序。The ordering of side effects is preserved with respect to volatile reads and writes (Volatile fields). 此外,如果执行环境可以推断出未使用表达式的值并且不会产生所需的副作用(包括通过调用方法或访问可变字段引起的任何副作用),则执行环境不需要计算表达式的一部分。Additionally, the execution environment need not evaluate part of an expression if it can deduce that that expression's value is not used and that no needed side effects are produced (including any caused by calling a method or accessing a volatile field). 当异步事件(如由另一个线程引发的异常)中断程序执行时,不保证可观察到的副作用在原始程序顺序中可见。When program execution is interrupted by an asynchronous event (such as an exception thrown by another thread), it is not guaranteed that the observable side effects are visible in the original program order.