基本概念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. @No__t-0 引數永遠不會是 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,而到達用來終止該方法的右大括弧(}),或執行沒有運算式的 @no__t 2 語句,則會產生終止狀態碼 0If 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_declarations 或type_parameters 引進此宣告空間。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.
  • 每個區塊switch_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_declarations 引進此宣告空間。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.
  • 每個區塊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_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值時,列舉成員宣告(列舉成員)的宣告順序是很重要的。Declaration order for enum member declarations (Enum members) is significant when constant_expression values are omitted.

命名空間的宣告空間是「開放式結束」,而兩個具有相同完整名稱的命名空間宣告會參與相同的宣告空間。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.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 和 @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. 不過,H 和 @no__t 1 方法有效,因為兩個 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. 實體的成員通常是透過使用以實體的參考開頭的限定名稱,後面接著 "." token,再加上成員名稱來提供。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 和間接基類 objectThe 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-0 的成員是 System.SByte 結構的成員。The members of sbyte are the members of the System.SByte struct.
  • @No__t-0 的成員是 System.Byte 結構的成員。The members of byte are the members of the System.Byte struct.
  • @No__t-0 的成員是 System.Int16 結構的成員。The members of short are the members of the System.Int16 struct.
  • @No__t-0 的成員是 System.UInt16 結構的成員。The members of ushort are the members of the System.UInt16 struct.
  • @No__t-0 的成員是 System.Int32 結構的成員。The members of int are the members of the System.Int32 struct.
  • @No__t-0 的成員是 System.UInt32 結構的成員。The members of uint are the members of the System.UInt32 struct.
  • @No__t-0 的成員是 System.Int64 結構的成員。The members of long are the members of the System.Int64 struct.
  • @No__t-0 的成員是 System.UInt64 結構的成員。The members of ulong are the members of the System.UInt64 struct.
  • @No__t-0 的成員是 System.Char 結構的成員。The members of char are the members of the System.Char struct.
  • @No__t-0 的成員是 System.Single 結構的成員。The members of float are the members of the System.Single struct.
  • @No__t-0 的成員是 System.Double 結構的成員。The members of double are the members of the System.Double struct.
  • @No__t-0 的成員是 System.Decimal 結構的成員。The members of decimal are the members of the System.Decimal struct.
  • @No__t-0 的成員是 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-0 和 string 的成員直接對應至其別名的類別類型成員:The members of object and string correspond directly to the members of the class types they alias:

  • @No__t-0 的成員是 System.Object 類別的成員。The members of object are the members of the System.Object class.
  • @No__t-0 的成員是 System.String 類別的成員。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 修飾詞。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".
  • 受保護的內部(表示 protected 或 internal),其選取方式是在成員宣告中包含 protected 和 @no__t 1 修飾詞。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, 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.

  • 命名空間隱含具有 public 宣告的存取範圍。Namespaces implicitly have public declared accessibility. 命名空間宣告上不允許有任何存取修飾詞。No access modifiers are allowed on namespace declarations.
  • 在編譯單位或命名空間中宣告的類型,可以有 public 或 @no__t 1 宣告的存取範圍,而且預設為 @no__t 2 宣告的存取範圍。Types declared in compilation units or namespaces can have public or internal declared accessibility and default to internal declared accessibility.
  • 類別成員可以具有五種宣告存取範圍的任何一種,而且預設為 @no__t 0 宣告的存取範圍。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 2 宣告的存取範圍,而且預設為 @no__t 3 宣告的存取範圍,因為結構是隱含密封的。Struct members can have public, internal, or private declared accessibility and default to private declared accessibility because structs are implicitly sealed. 結構中引進的結構成員(也就是,不是由該結構繼承)不能有 protected 或 @no__t 1 宣告的存取範圍。Struct members introduced in a struct (that is, not inherited by that struct) cannot have protected or protected internal declared accessibility. (請注意,宣告為結構成員的型別可以有 publicinternal 或 @no__t 2 宣告的存取範圍,而宣告為命名空間成員的型別只能有 publicinternal 宣告的存取範圍)。(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.)
  • 介面成員隱含具有 public 宣告的存取範圍。Interface members implicitly have public declared accessibility. 介面成員宣告上不允許有任何存取修飾詞。No access modifiers are allowed on interface member declarations.
  • 列舉成員隱含具有 public 宣告的存取範圍。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 中宣告之最上層未系結類型 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 的宣告存取範圍是 publicT 的存取範圍定義域就是 P 的程式文字,以及參考 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 的宣告存取範圍是 internalT 的存取範圍領域就是 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 的 @no__t 類型中宣告的嵌套成員 M 的存取範圍定義域,如下所示(請注意,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 的宣告存取範圍是 publicM 的存取範圍領域就是 T 的存取範圍領域。If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.
  • 如果 M 的宣告存取範圍是 protected internal,請讓 D 成為 P 的程式文字和任何衍生自 T 之類型的程式文字的聯集,而這是在 P 外部宣告。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-0 的存取範圍定義域是 T 的存取範圍網域與 D 的交集。The accessibility domain of M is the intersection of the accessibility domain of T with D.
  • 如果 M 的宣告存取範圍是 protected,請讓 D 成為 T 的程式文字和任何衍生自 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-0 的存取範圍定義域是 T 的存取範圍網域與 D 的交集。The accessibility domain of M is the intersection of the accessibility domain of T with D.
  • 如果 M 的宣告存取範圍是 internalM 的存取範圍領域是 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 的宣告存取範圍是 privateM 的存取範圍領域就是 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 public,則允許存取。Then, if M is public, the access is permitted.
  • 否則,如果 Mprotected internal,則允許存取(如果是在宣告 M 的程式中),或是發生在衍生自類別的類別中(其中已宣告 M,並會透過衍生類別類型進行)(Protected實例成員的存取權)。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).
  • 否則,如果 Mprotected,則如果在宣告 M 的類別內,或在衍生自類別的類別(其中已宣告了 M,並透過衍生類別類型執行)中,就會允許存取(Protected實例成員的存取權)。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).
  • 否則,如果 Minternal,則允許在宣告 M 的程式中進行存取。Otherwise, if M is internal, the access is permitted if it occurs within the program in which M is declared.
  • 否則,如果 Mprivate,則如果在宣告 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-0、`B`、`B.X`、`B.Y`、`B.C`、`B.C.X` 和 B.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-0 的存取範圍網域是 A 的程式文字。The accessibility domain of A.Z is the program text of A.
  • @No__t-0 的存取範圍網域和 B.DB 的程式文字,包括 B.CB.D 的程式文字。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-0 的存取範圍網域是 B.C 的程式文字。The accessibility domain of B.C.Z is the program text of B.C.
  • @No__t-0 的存取範圍網域和 B.D.YB 的程式文字,包括 B.CB.D 的程式文字。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-0 的存取範圍網域是 B.D 的程式文字。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
    }
}

@no__t 0 類別會從 @no__t 2 類別繼承 x 的私用成員。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. 因此,b.x 的存取會成功在 A.F 方法中,但會在 @no__t 2 方法中失敗。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 實例成員在宣告它的類別的程式文字之外存取時,以及在宣告的程式文字外部存取 @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.

Let 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. Dclass_body中,M 的存取權可以採用下列其中一種格式:Within the class_body of D, access to M can take one of the following forms:

  • 不合格的type_name或格式為 Mprimary_expressionAn unqualified type_name or primary_expression of the form M.
  • @No__t-1 格式的primary_expression ,前提是 E 的類型為 T,或衍生自 T 的類別,其中 T 是類別類型 D,或從 D 所構成的類別類型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
  • @No__t-1 格式的primary_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 中,可以透過 AB 的實例存取 x,因為在任一情況下,都會透過 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 中,無法透過 A 的實例存取 x,因為 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. 換句話說,如果在可存取 M 的所有內容中,T 可供存取,則 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 {...}

@no__t 0 類別會導致編譯時期錯誤,因為 A 的存取權至少不如 Bthe 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.

雖然 out 和 @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. 如果兩個具有 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)上執行,這不會提供方法來定義只在 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. 因此,在單一類型中宣告的成員,在簽章中可能不會單獨受到 objectdynamic 的差異。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 和 @no__t 1 參數修飾詞(方法參數)都是簽章的一部分。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),因為它們的簽章不同于 refoutHowever, 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_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_declarations。The 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_directiveusing指示詞)所定義或匯入之名稱的範圍會延伸到compilation_unitnamespace_bodynamespace_member_declarations,其中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_clauses 和class_body class_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_clauses 和struct_body ,屬於這struct_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_clauses 和interface_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_clause delegate_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_declaration列舉成員)所宣告的成員範圍是宣告發生所在的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_declaration區塊The scope of a parameter declared in an operator_declaration (Operators) is the block of that operator_declaration.
  • constructor_declaration中宣告的參數範圍(實例的程式,也就是該constructor_declarationconstructor_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中宣告的參數範圍(匿名函數運算式)是該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_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.
  • 在 @no__t 1 語句(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.
  • 在 @no__t 1 語句(for 語句)的for_initializer中宣告的區域變數範圍是for_initializerfor_conditionfor_iterator,以及的包含語句for 語句。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_statementq之一部分之變數的範圍是由指定結構的展開所決定。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 會在宣告之前參考 iHere, 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,並在類型內容中參考類別 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 中所宣告的 F,因為內部宣告會隱藏所有 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
}

DerivedF 的宣告會導致回報警告。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 中的 F 是 "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 的宣告會隱藏繼承自 BaseF,但因為 Derived 中新的 F 具有私用存取權,所以其範圍不會延伸至 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 ,而 <A1, ..., Ak> 是選擇性的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的格式為 I,或形式 I<A1, ..., Ak>If the namespace_or_type_name is of the form I or of the form I<A1, ..., Ak>:
    • 如果 K 為零,且namespace_or_type_name出現在泛型方法宣告(方法)中,而且該宣告包含名稱為 @ no__t-4 的型別參數(型別參數),則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-1 (實例類型),從該類型宣告的實例類型開始,然後繼續每個的實例類型。封入類別或結構宣告(如果有的話):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):
      • 如果 K 為零,且 T 的宣告包含名稱為 @ no__t-2 的類型參數,則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 或其任何基底類型包含具有 name @ 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-0,從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:
      • 如果 K 為零,且 I 是 @ no__t-2 中的命名空間名稱,則:If K is zero and I is the name of a namespace in N, then:
        • 如果發生namespace_or_type_name的位置是以 N 的命名空間宣告括住,且命名空間宣告包含extern_alias_directiveusing_alias_directive ,而該名稱與 @ no 關聯具有命名空間或類型的 __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-1 的可存取類型和 K @ no__t-3type 參數,則:Otherwise, if N contains an accessible type having name I and K type parameters, then:
        • 如果 K 為零,且發生namespace_or_type_name的位置是以 N 的命名空間宣告括住,且命名空間宣告包含extern_alias_directiveusing_alias_directive ,將名稱 @ no__t-5 關聯至命名空間或類型,然後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:
        • 如果 K 為零,且命名空間宣告包含extern_alias_directiveusing_alias_directive ,其會將名稱 @ no__t-3 與匯入的命名空間或類型產生關聯,則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_directive所匯入的命名空間和類型宣告,只包含一個名稱為 @ no__t-2 且 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_directive所匯入的命名空間和類型宣告包含一個以上名稱為 @ no__t-2 且 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的格式為 N.I,或形式 N.I<A1, ..., Ak>Otherwise, the namespace_or_type_name is of the form N.I or of the form N.I<A1, ..., Ak>. N 會第一次解析為namespace_or_type_nameN is first resolved as a namespace_or_type_name. 如果 N 的解決方式不成功,就會發生編譯時期錯誤。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:
    • 如果 K 為零,且 N 參考命名空間,而 N 包含名為 I 的嵌套命名空間,則namespace_or_type_name會參考該 nested 命名空間。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 指的是命名空間,而 N 包含具有 name @ no__t-2 和 K @ no__t-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 或其任何基類包含具有 name @ no__t-2 和 K @ 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 的基類規格中判斷 N.I 的意義,則 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).
    • 否則,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_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_name是表單T typeof_expression 的(引數清單1)中typeof(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.

換句話說,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:

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

建立類別的實例 A 和類別的實例 Bcreates an instance of class A and an instance of class B. 當指派 null 的值給 b 的變數時,這些物件就會成為垃圾收集的資格,因為在這段時間之後,任何使用者撰寫的程式碼都無法存取它們。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

請注意,雖然 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. 在此情況下,執行 @no__t 0 的「析構函式」會導致先前未使用的 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.RefAAfter 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.

使用析構函數的替代方法是讓類別實作為 @no__t 0 介面。An alternative to using destructors is to let a class implement the System.IDisposable interface. 這可讓物件的用戶端判斷何時釋放物件的資源,通常是以 @no__t 0 的語句(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. 副作用會定義為 volatile 欄位的讀取或寫入、對非 volatile 變數的寫入、對外部資源的寫入,以及擲回例外狀況。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. 這些副作用的順序必須保留的關鍵執行點是變動性欄位(volatile 欄位)、@no__t 1 語句(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).
  • 副作用的順序會根據變動性讀取和寫入(volatile 欄位)來保留。The ordering of side effects is preserved with respect to volatile reads and writes (Volatile fields). 此外,如果執行環境可以推算運算式的值未使用,而且不會產生任何所需的副作用(包括任何因呼叫方法或存取 volatile 欄位所造成的結果),則不需要評估運算式的一部分。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.