基本概念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) {...}
如图所示,入口点可以选择返回 int
值。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[]
. 如果正式参数存在,则执行环境创建并传递一个参数,该 string[]
参数包含在启动应用程序时指定的命令行参数。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. string[]
参数决不会为 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. 但是,在一个程序中,任何类或结构都不能包含多个名为的方法, Main
该方法的定义将其限定为作为应用程序入口点使用。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. 但允许使用的其他重载版本, Main
但前提是它们具有多个参数,或者其唯一参数不是类型 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. 其中的多个类或结构可能包含一个名为的方法,该方法的 Main
定义将其限定为作为应用程序入口点使用。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
到达右大括号后 (}
) 终止该方法或执行 return
没有表达式的语句时,将导致终止状态代码 0
。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_declaration 的 namespace_member_declaration 是单个组合声明空间的成员,称为 全局声明空间。Within all source files of a program, namespace_member_declaration s with no enclosing namespace_declaration are members of a single combined declaration space called the global declaration space.
- 在程序的所有源文件中,在具有相同完全限定的命名空间名称的 namespace_declaration 中 namespace_member_declaration s 是单个组合声明空间的成员。Within all source files of a program, namespace_member_declaration s within namespace_declaration s 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_declaration s、 struct_member_declaration s、 interface_member_declaration s 或 type_parameter 引入到此声明空间。Names are introduced into this declaration space through class_member_declaration s, struct_member_declaration s, interface_member_declaration s, or type_parameter s. 除了重载实例构造函数声明和静态构造函数声明,类或结构不能包含与类或结构同名的成员声明。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_parameter s 和 parameter_array s) 和 type_parameter。Names are introduced into this declaration space through formal parameters (fixed_parameter s and parameter_array s) and type_parameter s.
- 每个枚举声明都将创建一个新的声明空间。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_parameter * s 和 parameter_array s) 和 type_parameter。Names are introduced into this declaration space through formal parameters (_fixed_parameter*s and parameter_array s) and type_parameter s. 函数成员或匿名函数(如果有)的主体被视为嵌套在局部变量声明空间内。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.
- 每个 块 或 switch_block ,以及 for、 foreach 和 using 语句,都将为局部变量和本地常量创建局部变量声明空间。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_declaration s 和 local_constant_declaration 引入到此声明空间。Names are introduced into this declaration space through local_variable_declaration s and local_constant_declaration s. 请注意,在函数成员或匿名函数的主体中发生的块嵌套在这些函数为其参数声明的局部变量声明空间内。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.
- 每个 块 或 switch_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_statement s, and the names are referenced through goto_statement s. 块的 标签声明空间 包括任何嵌套块。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 值时,枚举成员声明 (枚举成员) 的声明顺序很重要。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.Customer
Megacorp.Data.Order
。The 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
和 G
方法会导致编译时错误,因为该名称 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. 不过, H
和 I
方法是有效的,因为这两个 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
object
。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:
- 的成员
sbyte
是结构的成员System.SByte
。The members ofsbyte
are the members of theSystem.SByte
struct. - 的成员
byte
是结构的成员System.Byte
。The members ofbyte
are the members of theSystem.Byte
struct. - 的成员
short
是结构的成员System.Int16
。The members ofshort
are the members of theSystem.Int16
struct. - 的成员
ushort
是结构的成员System.UInt16
。The members ofushort
are the members of theSystem.UInt16
struct. - 的成员
int
是结构的成员System.Int32
。The members ofint
are the members of theSystem.Int32
struct. - 的成员
uint
是结构的成员System.UInt32
。The members ofuint
are the members of theSystem.UInt32
struct. - 的成员
long
是结构的成员System.Int64
。The members oflong
are the members of theSystem.Int64
struct. - 的成员
ulong
是结构的成员System.UInt64
。The members ofulong
are the members of theSystem.UInt64
struct. - 的成员
char
是结构的成员System.Char
。The members ofchar
are the members of theSystem.Char
struct. - 的成员
float
是结构的成员System.Single
。The members offloat
are the members of theSystem.Single
struct. - 的成员
double
是结构的成员System.Double
。The members ofdouble
are the members of theSystem.Double
struct. - 的成员
decimal
是结构的成员System.Decimal
。The members ofdecimal
are the members of theSystem.Decimal
struct. - 的成员
bool
是结构的成员System.Boolean
。The members ofbool
are the members of theSystem.Boolean
struct.
枚举成员Enumeration members
枚举的成员是枚举中声明的常量,以及从枚举的直接基类 System.Enum
和间接基类和继承的成员 System.ValueType
object
。The 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.
和的成员 object
string
直接对应于其别名的类类型的成员:The members of object
and string
correspond directly to the members of the class types they alias:
- 的成员
object
是类的成员System.Object
。The members ofobject
are the members of theSystem.Object
class. - 的成员
string
是类的成员System.String
。The members ofstring
are the members of theSystem.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
在成员声明中包含修饰符来选择。Public, which is selected by including apublic
modifier in the member declaration. 的直观含义public
为 "访问不受限制"。The intuitive meaning ofpublic
is "access not limited". - Protected:通过
protected
在成员声明中包含修饰符来选择。Protected, which is selected by including aprotected
modifier in the member declaration. 的直观含义protected
为 "访问限制为包含类或派生自包含类的类型"。The intuitive meaning ofprotected
is "access limited to the containing class or types derived from the containing class". - 内部,通过
internal
在成员声明中包含修饰符来选择。Internal, which is selected by including aninternal
modifier in the member declaration. 的直观含义internal
为 "访问此程序限制"。The intuitive meaning ofinternal
is "access limited to this program". - 受保护的内部 (表示受保护的或内部) ,这是通过
protected
在成员声明中同时包含和修饰符来选择的internal
。Protected internal (meaning protected or internal), which is selected by including both aprotected
and aninternal
modifier in the member declaration. 的直观含义protected internal
为 "访问此程序或派生自包含类的类型"。The intuitive meaning ofprotected internal
is "access limited to this program or types derived from the containing class". - Private,通过
private
在成员声明中包含修饰符来选择。Private, which is selected by including aprivate
modifier in the member declaration. 的直观含义private
为 "访问限制为包含类型"。The intuitive meaning ofprivate
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.
- 命名空间隐式
public
声明了可访问性。Namespaces implicitly havepublic
declared accessibility. 命名空间声明中不允许使用访问修饰符。No access modifiers are allowed on namespace declarations. - 在编译单元或命名空间中声明的类型可以具有
public
或internal
声明可访问性,并且默认为internal
声明的可访问性。Types declared in compilation units or namespaces can havepublic
orinternal
declared accessibility and default tointernal
declared accessibility. - 类成员可以具有五种声明的可访问性和默认值为
private
声明的可访问性。Class members can have any of the five kinds of declared accessibility and default toprivate
declared accessibility. (请注意,声明为类成员的类型可以具有五种声明可访问性中的任何一种,而声明为命名空间成员的类型只能具有public
或声明可internal
访问性。 ) (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 onlypublic
orinternal
declared accessibility.) - 结构成员可以具有
public
、internal
或声明的可private
访问性,并且默认为已private
声明的可访问性,因为结构被隐式密封。Struct members can havepublic
,internal
, orprivate
declared accessibility and default toprivate
declared accessibility because structs are implicitly sealed. 结构成员是在结构 (中引入的,而不是由该结构继承) 无法具有protected
或protected internal
声明可访问性。Struct members introduced in a struct (that is, not inherited by that struct) cannot haveprotected
orprotected internal
declared accessibility. (请注意,声明为结构成员的类型可以具有public
、internal
或private
声明的可访问性,而声明为命名空间成员的类型只能具有public
或声明可internal
访问性。 ) (Note that a type declared as a member of a struct can havepublic
,internal
, orprivate
declared accessibility, whereas a type declared as a member of a namespace can have onlypublic
orinternal
declared accessibility.) - 接口成员隐式
public
声明了可访问性。Interface members implicitly havepublic
declared accessibility. 接口成员声明中不允许使用访问修饰符。No access modifiers are allowed on interface member declarations. - 枚举成员隐式具有
public
声明的可访问性。Enumeration members implicitly havepublic
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 * s 中包含的所有程序文本, (包括在该类型) 中嵌套的类型。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_declaration*s of that type (including, possibly, types that are nested within the type).
预定义类型的可访问域 (如 object
、 int
或 double
) 无限制。The accessibility domain of a predefined type (such as object
, int
, or double
) is unlimited.
在程序中声明的顶级未绑定类型的可访问域 T
) (绑定类型和未绑定类型 的 P
定义,如下所示: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
为,则的public
可访问域T
是的程序文本P
和引用的任何程序P
。If the declared accessibility ofT
ispublic
, the accessibility domain ofT
is the program text ofP
and any program that referencesP
. - 如果
T
的已声明可访问性为internal
,则T
的可访问域就是P
的程序文本。If the declared accessibility ofT
isinternal
, the accessibility domain ofT
is the program text ofP
.
从这些定义开始,顶级未绑定类型的可访问域始终至少是声明该类型的程序的程序文本。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
.
在程序内的类型中声明的嵌套成员的可访问域 M
T
P
定义如下 (说明 M
自身可能是类型) :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 ofM
ispublic
, the accessibility domain ofM
is the accessibility domain ofT
. - 如果的已声明可访问性
M
为protected internal
,则允许D
是的程序文本P
和从派生的任何类型的程序文本的并集T
P
。If the declared accessibility ofM
isprotected internal
, letD
be the union of the program text ofP
and the program text of any type derived fromT
, which is declared outsideP
. 的可访问域M
是的可访问域的交集T
D
。The accessibility domain ofM
is the intersection of the accessibility domain ofT
withD
. - 如果的已声明可访问性
M
为protected
,则允许D
是的程序文本T
和从派生的任何类型的程序文本的并集T
。If the declared accessibility ofM
isprotected
, letD
be the union of the program text ofT
and the program text of any type derived fromT
. 的可访问域M
是的可访问域的交集T
D
。The accessibility domain ofM
is the intersection of the accessibility domain ofT
withD
. - 如果
M
的已声明可访问性为internal
,则M
的可访问域就是T
的可访问域与P
的程序文本之间的交集。If the declared accessibility ofM
isinternal
, the accessibility domain ofM
is the intersection of the accessibility domain ofT
with the program text ofP
. - 如果
M
的已声明可访问性为private
,则M
的可访问域就是T
的程序文本。If the declared accessibility ofM
isprivate
, the accessibility domain ofM
is the program text ofT
.
从这些定义开始,嵌套成员的可访问域始终至少是声明该成员的类型的程序文本。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, ifM
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
为public
,则允许访问。Then, ifM
ispublic
, the access is permitted. - 否则,如果
M
为protected internal
,则允许访问,如果它出现在声明的程序中M
,或在派生自类的类派生的类中,并在派生类类型的类中发生,M
(对实例成员) 的保护访问 。Otherwise, ifM
isprotected internal
, the access is permitted if it occurs within the program in whichM
is declared, or if it occurs within a class derived from the class in whichM
is declared and takes place through the derived class type (Protected access for instance members). - 否则,如果
M
为protected
,则允许访问,如果它发生在已声明的类中,或在派生自类的派生自的类中,M
并在派生类类型的类中发生,则M
) 的 实例成员 (受保护的访问 。Otherwise, ifM
isprotected
, the access is permitted if it occurs within the class in whichM
is declared, or if it occurs within a class derived from the class in whichM
is declared and takes place through the derived class type (Protected access for instance members). - 否则,如果
M
为internal
,则允许访问,如果它发生在声明的程序内M
。Otherwise, ifM
isinternal
, the access is permitted if it occurs within the program in whichM
is declared. - 否则,如果
M
为private
,则允许访问,如果在声明的类型内发生访问M
。Otherwise, ifM
isprivate
, the access is permitted if it occurs within the type in whichM
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:
- 和的可访问
A
域A.X
不受限制。The accessibility domain ofA
andA.X
is unlimited. - 、、、、、和的可访问域
A.Y
B
B.X
B.Y
B.C
B.C.X
B.C.Y
是包含程序的程序文本。The accessibility domain ofA.Y
,B
,B.X
,B.Y
,B.C
,B.C.X
, andB.C.Y
is the program text of the containing program. - 的可访问域
A.Z
是的程序文本A
。The accessibility domain ofA.Z
is the program text ofA
. - 和的可访问
B.Z
域B.D
是的程序文本B
,包括和的程序文本B.C
B.D
。The accessibility domain ofB.Z
andB.D
is the program text ofB
, including the program text ofB.C
andB.D
. - 的可访问域
B.C.Z
是的程序文本B.C
。The accessibility domain ofB.C.Z
is the program text ofB.C
. - 和的可访问
B.D.X
域B.D.Y
是的程序文本B
,包括和的程序文本B.C
B.D
。The accessibility domain ofB.D.X
andB.D.Y
is the program text ofB
, including the program text ofB.C
andB.D
. - 的可访问域
B.D.Z
是的程序文本B.D
。The accessibility domain ofB.D.Z
is the program text ofB.D
.
如示例所示,成员的可访问域绝不会超出包含类型的可访问域。As the example illustrates, the accessibility domain of a member is never larger than that of a containing type. 例如,即使所有 X
成员均具有公开声明的可访问性,但所有成员都具有受 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
类从类继承私有成员 x
A
。the B
class inherits the private member x
from the A
class. 由于成员是私有的,因此只能在的 class_body 内访问 A
。Because the member is private, it is only accessible within the class_body of A
. 因此,对方法的访问 b.x
会成功 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
如果在 protected
声明实例成员的类的程序文本的外部访问该实例成员,并且在声明该实例成员的程序的 protected internal
程序文本的外部访问该实例成员,则必须在从其声明的类派生的类声明中进行访问。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.
允许 B
使用声明受保护实例成员的基类 M
,并使 D
其成为派生自的类 B
。Let B
be a base class that declares a protected instance member M
, and let D
be a class that derives from B
. 在 class_body 中 D
,访问 M
可以采用以下形式之一:Within the class_body of D
, access to M
can take one of the following forms:
- 格式的非限定 type_name 或 primary_expression
M
。An unqualified type_name or primary_expression of the formM
. - 如果的
E.M
类型为或从派生的类,则为窗体的 primary_expressionE
T
T
,其中T
是类类型D
或构造自的类类型D
A primary_expression of the formE.M
, provided the type ofE
isT
or a class derived fromT
, whereT
is the class typeD
, or a class type constructed fromD
- 窗体的 primary_expression
base.M
。A primary_expression of the formbase.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
,可以 x
通过和的实例进行访问 A
B
,因为在任一情况下,都可以通过的实例 A
或从派生的类进行访问 A
。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
,不能通过的实例进行访问 x
,因为不是 A
A
从派生的 B
。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";
}
}
允许使用三个赋值, x
因为它们都是通过从泛型类型构造的类类型的实例进行的。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
是的可访问域的超集,则称为至少可作为成员或类型访问的类型 M
。A 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
. 换句话说,至少可访问,就像可访问的 T
M
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() {...}
}
H
中的方法 B
导致编译时错误,这是因为返回类型 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, theparams
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 theparams
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 theparams
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.
尽管 out
和 ref
参数修饰符被视为签名的一部分,但在单个类型中声明的成员不能仅在和中不同 ref
out
。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
. 如果两个成员是在同一类型中声明的,并且具有修饰符的两个方法中的所有参数 out
都已更改为修饰符,则会发生编译时错误 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. 对于签名匹配的其他目的 (例如,隐藏或重写) , ref
并且 out
将被视为签名的一部分且不匹配。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) ,这并不提供一种方法来定义仅与和不同的方法 ref
out
。 ) (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
.)
对于签名,类型 object
和 dynamic
被视为相同。For the purposes of signatures, the types object
and dynamic
are considered the same. 因此,在单个类型中声明的成员可以在仅通过和的签名中有所不同 object
dynamic
。Members 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
}
请注意, ref
out
(方法参数) 的任何和参数修饰符均为签名的一部分。Note that any ref
and out
parameter modifiers (Method parameters) are part of a signature. 因此, F(int)
和 F(ref int)
是唯一的签名。Thus, F(int)
and F(ref int)
are unique signatures. 但是, F(ref int)
和 F(out int)
无法在同一接口内声明,因为它们的签名仅与 ref
和不同 out
。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
修饰符不是签名的一部分,因此不可能仅基于返回类型或修饰符的包含或排除重载 params
。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)
会 F(params string[])
导致编译时错误。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_declaration 中 namespace_member_declaration 声明的命名空间成员的范围
N
是完全限定名称为或开头的每个 namespace_declaration 的 namespace_bodyN
N
,后跟一个句点。The scope of a namespace member declared by a namespace_member_declaration within a namespace_declaration whose fully qualified name isN
is the namespace_body of every namespace_declaration whose fully qualified name isN
or starts withN
, followed by a period. - Extern_alias_directive 定义的名称的作用域超出了其立即包含编译单元或命名空间正文的 using_directive s、 global_attributes 和 namespace_member_declaration。The scope of name defined by an extern_alias_directive extends over the using_directive s, global_attributes and namespace_member_declaration s 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_unit 发生 的 namespace_body 或 using_directive 的 namespace_member_declaration。The scope of a name defined or imported by a using_directive (Using directives) extends over the namespace_member_declaration s of the compilation_unit or namespace_body in which the using_directive occurs. Using_directive 可以使零个或多个命名空间、类型或成员名称在特定 compilation_unit 或 namespace_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_unit 或 namespace_body 。In other words, a using_directive is not transitive but rather affects only the compilation_unit or namespace_body in which it occurs.
- Type_parameter_list 在 class_declaration (类声明中声明的类型形参的作用域) 是该 class_base 的 type_parameter_constraints_clause、 class_body 和 class_declaration 。The scope of a type parameter declared by a type_parameter_list on a class_declaration (Class declarations) is the class_base, type_parameter_constraints_clause s, and class_body of that class_declaration.
- 由 struct_declaration (结构声明) 的 type_parameter_list 声明的类型形参的作用域是该 struct_interfaces 的 type_parameter_constraints_clause、 struct_body 和 struct_declaration 。The scope of a type parameter declared by a type_parameter_list on a struct_declaration (Struct declarations) is the struct_interfaces, type_parameter_constraints_clause s, and struct_body of that struct_declaration.
- 由 interface_declaration (接口声明上的 type_parameter_list 声明的类型参数的范围) 是该 interface_base 的 type_parameter_constraints_clause、 interface_body 和 interface_declaration 。The scope of a type parameter declared by a type_parameter_list on an interface_declaration (Interface declarations) is the interface_base, type_parameter_constraints_clause s, and interface_body of that interface_declaration.
- Delegate_declaration (委托) 声明上的 type_parameter_list 声明的类型形参的作用域是该 return_type 的 formal_parameter_list、 type_parameter_constraints_clause 和 delegate_declaration。The 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_clause s of that delegate_declaration.
- Class_member_declaration (类体) 声明的成员的作用域是在其中进行声明的 class_body 。The scope of a member declared by a class_member_declaration (Class body) is the class_body in which the declaration occurs. 此外,类成员的范围扩展到可访问性域 (包含在该成员的 可访问性域) 中的派生类的 class_body 。In 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_body 。The scope of a member declared by a struct_member_declaration (Struct members) is the struct_body in which the declaration occurs.
- Enum_member_declaration (枚举成员声明的成员的作用域) 是在其中进行声明的 enum_body 。The scope of a member declared by an enum_member_declaration (Enum members) is the enum_body in which the declaration occurs.
- ) method_declaration (方法中声明的参数的作用域是该 method_declaration 的 method_body 。The scope of a parameter declared in a method_declaration (Methods) is the method_body of that method_declaration.
- Indexer_declaration (索引器) 中声明的参数的作用域是该 indexer_declaration 的 accessor_declarations 。The scope of a parameter declared in an indexer_declaration (Indexers) is the accessor_declarations of that indexer_declaration.
- 在 operator_declaration (Operators) 中声明的参数的作用域是该 operator_declaration 的 块。The scope of a parameter declared in an operator_declaration (Operators) is the block of that operator_declaration.
- 在 constructor_declaration (实例构造函数中声明的参数的作用域) 是该 constructor_declaration 的 constructor_initializer 和 块。The scope of a parameter declared in a constructor_declaration (Instance constructors) is the constructor_initializer and block of that constructor_declaration.
- 在 lambda_expression 中声明的参数的作用域 (匿名函数表达式) 是该的 anonymous_function_body lambda_expressionThe 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_expression 的 块。The 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_block 中声明的局部变量的作用域
switch
) 为 switch_block。The scope of a local variable declared in a switch_block of aswitch
statement (The switch statement) is the switch_block. - 在语句的 for_initializer 中声明的局部变量的作用域
for
(for 语句) 是语句的 for_initializer、 for_condition、 for_iterator 和包含的 语句for
。The scope of a local variable declared in a for_initializer of afor
statement (The for statement) is the for_initializer, the for_condition, the for_iterator, and the contained statement of thefor
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_statement、 using_statement、 lock_statement 或 query_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
i
。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
上面的方法中,第一个具体赋值语句 i
并不引用在外部范围中声明的字段。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
是有效的, j
因为在 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
,并在类型上下文中引用以引用类 A
。the 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. 此类声明会使原始实体变成 *hidden _。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)
调用 F
中声明的, Inner
因为 F
内部声明隐藏了的所有外部匹配项。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
}
中的声明 F
Derived
会导致报告警告。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
引入了 F
在早期版本的类中不存在的方法,因此可能会出现上述情况。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() {}
}
new
修饰符指示 F
中的 Derived
为 "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
}
在上面的示例中,中的 F
声明 Derived
隐藏了 F
从继承的 Base
,但由于中的新 F
Derived
具有 private 权限,其作用域不会扩展到 MoreDerived
。In 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
. 因此,中的 F()
调用 MoreDerived.G
有效并且将调用 Base.F
。Thus, the call F()
in MoreDerived.G
is valid and will invoke Base.F
.
命名空间和类型名称Namespace and type names
C # 程序中的多个上下文需要指定 namespace_name 或 type_name 。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_name 。A namespace_name is a namespace_or_type_name that refers to a namespace. 按照下面所述的解决方法, namespace_name 的 namespace_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_name 。A type_name is a namespace_or_type_name that refers to a type. 按照下面所述的解决方法, type_name 的 namespace_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
是单个标识符, N
是 namespace_or_type_name , <A1, ..., Ak>
是可选 type_argument_list。where 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 的格式为
I
或格式为I<A1, ..., Ak>
:If the namespace_or_type_name is of the formI
or of the formI<A1, ..., Ak>
:- 如果
K
为零,并且 namespace_or_type_name 出现在泛型方法声明中 (方法) ,并且如果该声明包含类型参数 (类型参数) 名称I
,则 namespace_or_type_name 引用该类型参数。IfK
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 nameI
, then the namespace_or_type_name refers to that type parameter. - 否则,如果 namespace_or_type_name 出现在类型声明内,则 (实例类型的每个实例类型
T
) ,从该类型声明的实例类型开始,并继续使用每个封闭类或结构 (声明的实例类型(如果有任何) ): Otherwise, if the namespace_or_type_name appears within a type declaration, then for each instance typeT
(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):- 如果
K
为零,的声明T
包含名为的类型参数I
,则 namespace_or_type_name 引用该类型参数。IfK
is zero and the declaration ofT
includes a type parameter with nameI
, then the namespace_or_type_name refers to that type parameter. - 否则,如果 namespace_or_type_name 出现在类型声明的主体中,
T
或者其任何基类型包含具有 name 和 type 参数的嵌套可访问类型I
K
,则 namespace_or_type_name 引用使用给定类型参数构造的类型。Otherwise, if the namespace_or_type_name appears within the body of the type declaration, andT
or any of its base types contain a nested accessible type having nameI
andK
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_name 的含义时,将忽略非类型成员 (常数、字段、方法、属性、索引器、运算符、实例构造函数、析构函数和静态构造函数) 和类型参数不同的类型成员。Note 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.
- 如果
- 如果前面的步骤不成功,则对于每个命名空间
N
,从 namespace_or_type_name 发生的命名空间开始,继续每个封闭命名空间 (如果任何) ,并且结束于全局命名空间,则将计算以下步骤,直到找到实体:If the previous steps were unsuccessful then, for each namespaceN
, 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:- 如果
K
为零,并且I
是中的命名空间的名称N
,则:IfK
is zero andI
is the name of a namespace inN
, then:- 如果 namespace_or_type_name 发生的位置由的命名空间声明括起来
N
,并且命名空间声明包含将名称与命名空间或类型相关联的 extern_alias_directive 或 using_alias_directiveI
,则 namespace_or_type_name 是不明确的,并发生编译时错误。If the location where the namespace_or_type_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with a namespace or type, then the namespace_or_type_name is ambiguous and a compile-time error occurs. - 否则, namespace_or_type_name 引用中名为的命名
I
空间N
。Otherwise, the namespace_or_type_name refers to the namespace namedI
inN
.
- 如果 namespace_or_type_name 发生的位置由的命名空间声明括起来
- 否则,如果
N
包含具有 name 和 type 参数的可访问类型I
K
,则:Otherwise, ifN
contains an accessible type having nameI
andK
type parameters, then:- 如果
K
为零,并且 namespace_or_type_name 的位置由的命名空间声明括起来,N
并且命名空间声明包含将名称与命名空间或类型相关联的 extern_alias_directive 或 using_alias_directiveI
,则 namespace_or_type_name 是不明确的,并发生编译时错误。IfK
is zero and the location where the namespace_or_type_name occurs is enclosed by a namespace declaration forN
and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
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 forN
:- 如果
K
为零,并且命名空间声明包含将名称与导入的命名空间或类型相关联的 extern_alias_directive 或 using_alias_directiveI
,则 namespace_or_type_name 引用该命名空间或类型。IfK
is zero and the namespace declaration contains an extern_alias_directive or using_alias_directive that associates the nameI
with an imported namespace or type, then the namespace_or_type_name refers to that namespace or type. - 否则,如果由 using_namespace_directive s 和 using_alias_directive s 的命名空间声明中的命名空间和类型声明都包含一个具有 name 和 type 参数的可访问类型
I
K
,则 namespace_or_type_name 引用使用给定类型参数构造的类型。Otherwise, if the namespaces and type declarations imported by the using_namespace_directive s and using_alias_directive s of the namespace declaration contain exactly one accessible type having nameI
andK
type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments. - 否则,如果 using_namespace_directive s 和命名空间声明的 using_alias_directive s 中导入的命名空间和类型声明包含具有 name 和 type 参数的多个可访问类型
I
K
,则 namespace_or_type_name 不明确,会发生错误。Otherwise, if the namespaces and type declarations imported by the using_namespace_directive s and using_alias_directive s of the namespace declaration contain more than one accessible type having nameI
andK
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 的格式为
N.I
或N.I<A1, ..., Ak>
。Otherwise, the namespace_or_type_name is of the formN.I
or of the formN.I<A1, ..., Ak>
.N
首先解析为 namespace_or_type_name。N
is first resolved as a namespace_or_type_name. 如果的解决方法N
不成功,则会发生编译时错误。If the resolution ofN
is not successful, a compile-time error occurs. 否则,N.I
或N.I<A1, ..., Ak>
按如下方式解决:Otherwise,N.I
orN.I<A1, ..., Ak>
is resolved as follows:- 如果
K
为零,并且N
引用命名空间并N
包含名为的嵌套命名空间I
,则 namespace_or_type_name 引用该嵌套命名空间。IfK
is zero andN
refers to a namespace andN
contains a nested namespace with nameI
, then the namespace_or_type_name refers to that nested namespace. - 否则,如果
N
引用命名空间并N
包含具有 name 和 type 参数的可访问类型I
K
,则 namespace_or_type_name 引用使用给定类型参数构造的类型。Otherwise, ifN
refers to a namespace andN
contains an accessible type having nameI
andK
type parameters, then the namespace_or_type_name refers to that type constructed with the given type arguments. - 否则,如果
N
引用的 (可能构造) 类或结构类型,N
或者其任何基类包含名称和类型参数的嵌套可访问类型I
K
,则 namespace_or_type_name 引用使用给定类型参数构造的类型。Otherwise, ifN
refers to a (possibly constructed) class or struct type andN
or any of its base classes contain a nested accessible type having nameI
andK
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
确定为解析的基类规范的一部分,则的N
直接基类被N
视为 (基类) 的对象。Note that if the meaning ofN.I
is being determined as part of resolving the base class specification ofN
then the direct base class ofN
is considered to be object (Base classes). - 否则,
N.I
是无效的 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_name 是
T
窗体的 namespace_or_type_name 中的T.I
,或The namespace_or_type_name is theT
in a namespace_or_type_name of the formT.I
, or - Namespace_or_type_name
T
在 typeof_expression (参数中列出了窗体的 1)typeof(T)
。The namespace_or_type_name is theT
in a typeof_expression (Argument lists1) of the formtypeof(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
是全局命名空间的成员,则其完全限定的名称为N
。IfN
is a member of the global namespace, its fully qualified name isN
. - 否则,其完全限定名称为
S.N
,其中S
是声明的命名空间或类型的完全限定名称N
。Otherwise, its fully qualified name isS.N
, whereS
is the fully qualified name of the namespace or type in whichN
is declared.
换句话说,的完全限定名 N
是 N
从全局命名空间开始的标识符的完整层次结构路径。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:
- 创建对象时,将为其分配内存,运行构造函数,并将对象视为实时对象。When the object is created, memory is allocated for it, the constructor is run, and the object is considered live.
- 如果对象或它的任何部分不能通过任何可能的执行继续进行访问,而不是运行析构函数,则该对象被视为不再使用,并可用于销毁。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.
- 一旦对象符合销毁条件,在某个以后未指定的时间,析构函数 (析构 函数) (如果该对象的任何) 运行。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.
- 一旦运行某个对象的析构函数,如果该对象或它的任何部分不能通过任何可能的执行继续进行访问,包括运行析构函数,则该对象将被视为不可访问,并且该对象便可用于收集。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.
- 最后,在对象变为符合集合条件后,垃圾回收器将释放与该对象关联的内存。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.GC
。The 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();
}
}
创建类的实例 A
和类的实例 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");
}
}
在上述程序中,如果垃圾回收器选择在的 A
析构函数之前运行的析构函数 B
,则此程序的输出可能是: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
请注意,虽然的实例 A
未被使用,并且其 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. 在这种情况下,运行的 B
析构函数导致 A
先前未使用的实例成为可从实时引用访问的实例 Test.RefA
。In 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
符合集合条件,但的实例不符合要求 A
,因为引用的是 Test.RefA
。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.