14 個命名空間
14.1 一般
C# 程式是使用命名空間來組織。 命名空間既做為程式的「內部」組織系統,又做為「外部」組織系統,用來呈現向其他程式公開的程序元素。
會提供 Using 指示詞 (~14.5) 來協助命名空間的使用。
14.2 編譯單位
compilation_unit包含零或多個extern_alias_directive,後面接著零或多個using_directive,後面接著零個或一個global_attributes后接零或多個namespace_member_declarations。 compilation_unit會定義輸入的整體結構。
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
;
C# 程式是由一或多個編譯單位所組成。 編譯 C# 程式時,所有編譯單位都會一起處理。 因此,編譯單位可以彼此相依,可能以迴圈方式。
編譯 單位的extern_alias_directive會影響 該編譯單位的using_directive、 global_attributes 和 namespace_member_declaration,但不會影響其他編譯單位。
編譯 單位的using_directive會影響 該編譯單位的global_attributes 和 namespace_member_declaration,但不會影響其他編譯單位。
編譯 單位的global_attributes (~22.3)允許指定目標元件和模組的屬性。 元件和模組可作為類型的實體容器。 元件可能包含數個實體個別的模組。
程式每個編譯單位的 namespace_member_declaration會為稱為全域命名空間的單一宣告空間貢獻成員。
範例:
// File A.cs: class A {} // File B.cs: class B {}
這兩個編譯單位會貢獻單一全域命名空間,在此案例中,宣告兩個具有完整名稱和
A
B
的類別。 由於這兩個編譯單位會參與相同的宣告空間,因此如果每個單位都包含同名成員的宣告,就會發生錯誤。end 範例
14.3 命名空間宣告
namespace_declaration包含關鍵詞命名空間,後面接著命名空間名稱和主體,選擇性地後面接著分號。
namespace_declaration
: 'namespace' qualified_identifier namespace_body ';'?
;
qualified_identifier
: identifier ('.' identifier)*
;
namespace_body
: '{' extern_alias_directive* using_directive*
namespace_member_declaration* '}'
;
namespace_declaration可能會以compilation_unit中的最上層宣告或另一個namespace_declaration內的成員宣告的形式發生。 當namespace_declaration當做compilation_unit的最上層宣告發生時,命名空間會成為全域命名空間的成員。 當namespace_declaration在另一個namespace_declaration內發生時,內部命名空間會成為外部命名空間的成員。 不論是哪一種情況,命名空間的名稱都應該在包含的命名空間內是唯一的。
命名空間是隱含的 public
,命名空間的宣告不能包含任何存取修飾詞。
在namespace_body內,選擇性using_directive會匯入其他命名空間、類型和成員的名稱,以便直接參考它們,而不是透過限定的名稱來參考。 選擇性 namespace_member_declaration會為命名空間的宣告空間貢獻成員。 請注意,所有 using_directive都應該出現在任何成員宣告之前。
namespace_declaration的qualified_identifier可以是單一標識碼或以 「.
標記分隔的標識碼序列」。 後者形式允許程式定義巢狀命名空間,而不需要語彙巢狀數個命名空間宣告。
範例:
namespace N1.N2 { class A {} class B {} }
在語意上相當於
namespace N1 { namespace N2 { class A {} class B {} } }
end 範例
命名空間是開放式的,而具有相同完整名稱的兩個命名空間宣告({7.8.2)則為相同的宣告空間({7.3)。
範例:在下列程式代碼中
namespace N1.N2 { class A {} } namespace N1.N2 { class B {} }
上述的兩個命名空間宣告會貢獻相同的宣告空間,在此案例中,宣告兩個具有完整名稱和
N1.N2.A
N1.N2.B
的類別。 由於這兩個宣告會參與相同的宣告空間,因此如果每個宣告都包含同名成員的宣告,就會發生錯誤。end 範例
14.4 Extern 別名指示詞
extern_alias_directive引進標識碼,做為命名空間的別名。 別名命名空間的規格是程式碼的外部,也適用於別名命名空間的巢狀命名空間。
extern_alias_directive
: 'extern' 'alias' identifier ';'
;
extern_alias_directive的範圍會延伸至using_directive s、global_attributes和namespace_member_declaration s,其立即包含compilation_unit或namespace_body。
在包含extern_alias_directive的編譯單位或命名空間主體內,extern_alias_directive引進的標識符可用來參考別名命名空間。 標識碼為 global
的編譯時間錯誤。
extern_alias_directive引進的別名與using_alias_directive引進的別名非常類似。 如需 extern_alias_directive 和 using_alias_directives 的詳細討論,請參閱 <14.5.2>。
alias
是內容關鍵詞 (~6.4.4),只有在緊接extern
extern_alias_directive中的 關鍵詞時,才有特殊意義。
如果程式宣告未提供外部定義的extern別名,就會發生錯誤。
範例:下列程式會宣告並使用兩個外部別名,
X
以及Y
,其中每個別名都代表不同命名空間階層的根目錄:extern alias X; extern alias Y; class Test { X::N.A a; X::N.B b1; Y::N.B b2; Y::N.C c; }
程式會宣告外部別名
X
和Y
的存在,但別名的實際定義位於程式外部。 同名N.B
類別現在可以當做X.N.B
和Y.N.B
參考,或使用命名空間別名限定符X::N.B
和Y::N.B
。 end 範例
14.5 Using 指示詞
14.5.1 一般
Using 指示詞 有助於使用在其他命名空間中定義的命名空間和類型。 使用 指示詞會影響 namespace_or_type_names ({7.8) 和 simple_names 的名稱解析程式({12.8.4),但與宣告不同,using_directive不會將新成員貢獻至使用編譯單位或命名空間的基礎宣告空間。
using_directive
: using_alias_directive
| using_namespace_directive
| using_static_directive
;
using_alias_directive (~14.5.2) 引進命名空間或類型的別名。
using_namespace_directive (~14.5.3) 會匯入命名空間的類型成員。
using_static_directive (\14.5.4) 會匯入類型的巢狀類型和靜態成員。
using_directive的範圍會延伸至其立即包含編譯單位或命名空間主體的namespace_member_declarations。 using_directive的範圍特別不包含其對等using_directive。 因此,對等 using_directive不會影響彼此,而且寫入的順序微不足道。 相反地,extern_alias_directive的範圍包含相同編譯單位或命名空間主體中定義的using_directive。
14.5.2 使用別名指示詞
using_alias_directive引進標識碼,做為命名空間或類型之別名的立即封入編譯單位或命名空間主體。
using_alias_directive
: 'using' identifier '=' namespace_or_type_name ';'
;
在包含using_alias_directive之編譯單位或命名空間主體中的全域屬性和成員宣告內,using_alias_directive引進的標識碼可用來參考指定的命名空間或類型。
範例:
namespace N1.N2 { class A {} } namespace N3 { using A = N1.N2.A; class B: A {} }
上述,在命名空間的成員宣告中
N3
,是的N1.N2.A
別名,A
因此 類別N3.B
衍生自 類別N1.N2.A
。 藉由建立 的別名R
N1.N2
,然後參考R.A
,即可取得相同的效果:namespace N3 { using R = N1.N2; class B : R.A {} }
end 範例
在using指示詞、編譯單位或命名空間主體中包含extern_alias_directive的全域屬性和成員宣告內,extern_alias_directive引進的標識碼可用來參考相關聯的命名空間。
範例:例如:
namespace N1 { extern alias N2; class B : N2::A {} }
以上,在命名空間的成員宣告內,是一些命名空間的
N1
別名,N2
其定義是程式原始程式碼外部的部分命名空間。 類別N1.B
衍生自 類別N2.A
。 藉由建立 的別名A
N2.A
,然後參考A
,即可取得相同的效果:namespace N1 { extern alias N2; using A = N2::A; class B : A {} }
end 範例
extern_alias_directive或using_alias_directive在特定編譯單位或命名空間主體內提供別名,但不會為基礎宣告空間貢獻任何新成員。 換句話說,別名指示詞不是可轉移的,而是只會影響發生它的編譯單位或命名空間主體。
範例:在下列程式代碼中
namespace N3 { extern alias R1; using R2 = N1.N2; } namespace N3 { class B : R1::A, R2.I {} // Error, R1 and R2 unknown }
別名
R1
指示詞的範圍,這些指示詞引進並R2
只擴充至包含它們的命名空間主體中的成員宣告,因此R1
在第R2
二個命名空間宣告中為未知。 不過,將別名指示詞放在包含編譯單位的 中,會導致別名在兩個命名空間宣告中變成可用:extern alias R1; using R2 = N1.N2; namespace N3 { class B : R1::A, R2.I {} } namespace N3 { class C : R1::A, R2.I {} }
end 範例
compilation_unit或namespace_body中的每個extern_alias_directive或using_alias_directive都會為立即封入compilation_unit或namespace_body的別名宣告空間 ({7.3) 提供名稱。 別名指示詞的標識碼在對應的別名宣告空間內應是唯一的。 別名標識碼在全域宣告空間或對應命名空間的宣告空間內不需要是唯一的。
範例:
extern alias X; extern alias Y; using X = N1.N2; // Error: alias X already exists class Y {} // Ok
使用名為 的
X
別名會造成錯誤,因為相同編譯單位中已經有名為X
的別名。 名為Y
的類別不會與名為Y
的extern 別名衝突,因為這些名稱會新增至不同的宣告空格。 前者會新增至全域宣告空間,後者會新增至這個編譯單位的別名宣告空間。當別名名稱符合命名空間成員的名稱時,應適當限定其中一項的使用方式:
namespace N1.N2 { class B {} } namespace N3 { class A {} class B : A {} } namespace N3 { using A = N1.N2; using B = N1.N2.B; class W : B {} // Error: B is ambiguous class X : A.B {} // Error: A is ambiguous class Y : A::B {} // Ok: uses N1.N2.B class Z : N3.B {} // Ok: uses N3.B }
在第二個命名空間主體中
N3
,不合格的使用B
會導致錯誤,因為N3
包含名為B
的成員和命名空間主體,也會宣告名稱為B
的別名;同樣地, 。A
N3.B
類別可以參考為N3.B
或global::N3.B
。 別名A
可用於 限定別名成員 (~14.8),例如A::B
。 別名B
基本上是無用的。 它不能用於 qualified_alias_member ,因為只有命名空間別名可用於 類型qualified_alias_member 和B
別名。end 範例
就像一般成員一樣,alias_directives引進的名稱會由巢狀範圍中的類似具名成員隱藏。
範例:在下列程式代碼中
using R = N1.N2; namespace N3 { class R {} class B: R.A {} // Error, R has no member A }
宣告中的
B
參考R.A
會導致編譯時期錯誤,因為R
參考 ,N3.R
而不是N1.N2
。end 範例
寫入extern_alias_directive的順序沒有意義。 同樣地,寫入using_alias_directive的順序沒有意義,但所有using_alias_directives都必須在相同的編譯單位或命名空間主體中所有extern_alias_directive之後。 using_alias_directive所參考之namespace_or_type_name的解析不會受到using_alias_directive本身或其他包含編譯單位或命名空間主體中其他using_directive的影響,但可能會受到立即包含編譯單位或命名空間主體中的 extern_alias_directive影響。 換句話說,會解析using_alias_directive的namespace_or_type_name,就像立即包含編譯單位或命名空間主體的 沒有using_directive,但具有正確的extern_alias_directive集。
範例:在下列程式代碼中
namespace N1.N2 {} namespace N3 { extern alias X; using R1 = X::N; // OK using R2 = N1; // OK using R3 = N1.N2; // OK using R4 = R2.N2; // Error, R2 unknown }
最後 一個using_alias_directive 會導致編譯時間錯誤,因為它不會受到上 一個using_alias_directive的影響。 第一個 using_alias_directive 不會產生錯誤,因為extern alias X的範圍包含 using_alias_directive。
end 範例
using_alias_directive可以建立任何命名空間或類型的別名,包括其出現的命名空間,以及該命名空間內巢狀的任何命名空間或類型。
透過別名存取命名空間或類型會產生與透過其宣告名稱存取該命名空間或類型完全相同的結果。
範例:指定
namespace N1.N2 { class A {} } namespace N3 { using R1 = N1; using R2 = N1.N2; class B { N1.N2.A a; // refers to N1.N2.A R1.N2.A b; // refers to N1.N2.A R2.A c; // refers to N1.N2.A } }
名稱
N1.N2.A
、R1.N2.A
和R2.A
都相等,且全都參考其完整名稱為N1.N2.A
的類別宣告。end 範例
雖然部分類型的每個部分 ({15.2.7) 都是在相同的命名空間內宣告,但元件通常會在不同的命名空間宣告內撰寫。 因此,每個元件都有不同的 extern_alias_directive和 using_directive。 在一個元件內解譯簡單名稱(~12.8.4)時,只會考慮該部分的命名空間主體和編譯單位的extern_alias_directives 和 using_directive 。 這可能會導致相同標識碼在不同部分有不同的意義。
範例:
namespace N { using List = System.Collections.ArrayList; partial class A { List x; // x has type System.Collections.ArrayList } } namespace N { using List = Widgets.LinkedList; partial class A { List y; // y has type Widgets.LinkedList } }
end 範例
使用別名可以命名封閉的建構型別,但無法命名未系結的泛型型別宣告,而不需提供類型自變數。
範例:
namespace N1 { class A<T> { class B {} } } namespace N2 { using W = N1.A; // Error, cannot name unbound generic type using X = N1.A.B; // Error, cannot name unbound generic type using Y = N1.A<int>; // Ok, can name closed constructed type using Z<T> = N1.A<T>; // Error, using alias cannot have type parameters }
end 範例
14.5.3 使用命名空間指示詞
using_namespace_directive會將命名空間中包含的型別匯入到立即封入編譯單位或命名空間主體中,讓每個類型的標識符不具資格即可使用。
using_namespace_directive
: 'using' namespace_name ';'
;
在包含using_namespace_directive之編譯單位或命名空間主體的成員宣告中,可以直接參考指定命名空間中包含的類型。
範例:
namespace N1.N2 { class A {} } namespace N3 { using N1.N2; class B : A {} }
上述,在命名空間中的成員宣告內
N3
,直接提供的N1.N2
型別成員,因此 類別N3.B
衍生自 類別N1.N2.A
。end 範例
using_namespace_directive會匯入指定命名空間中包含的型別,但特別不會匯入巢狀命名空間。
範例:在下列程式代碼中
namespace N1.N2 { class A {} } namespace N3 { using N1; class B : N2.A {} // Error, N2 unknown }
using_namespace_directive會匯入 中包含的
N1
型別,但不會匯入巢狀中的N1
命名空間。 因此,宣告B
中的 參考N2.A
會導致編譯時期錯誤,因為沒有名為N2
的成員位於範圍內。end 範例
不同於using_alias_directive,using_namespace_directive可以匯入已在封入編譯單位或命名空間主體內定義標識符的類型。 實際上,由using_namespace_directive匯入的名稱會由封入編譯單位或命名空間主體中的類似具名成員隱藏。
範例:
namespace N1.N2 { class A {} class B {} } namespace N3 { using N1.N2; class A {} }
在這裡,在命名空間中的成員宣告中
N3
,A
參考N3.A
而不是N1.N2.A
。end 範例
因為當多個匯入的命名空間引進相同的類型名稱時,名稱可能會模棱兩可, 因此using_alias_directive 有助於釐清參考。
範例:在下列程式代碼中
namespace N1 { class A {} } namespace N2 { class A {} } namespace N3 { using N1; using N2; class B : A {} // Error, A is ambiguous }
N1
和 都包含N2
成員A
,而且 因為N3
匯入兩者,A
因此參考 中的N3
是編譯時期錯誤。 在此情況下,衝突可以透過的參考A
資格來解決,或藉由引進可挑選特定A
之using_alias_directive來解決。 例如:namespace N3 { using N1; using N2; using A = N1.A; class B : A {} // A means N1.A }
end 範例
此外,當相同編譯單位或命名空間主體中由 using_namespace_directive s 或 using_static_directive匯入的多個命名空間或類型包含相同名稱的類型或成員時,將該名稱的參考視為simple_name模棱兩可。
範例:
namespace N1 { class A {} } class C { public static int A; } namespace N2 { using N1; using static C; class B { void M() { A a = new A(); // Ok, A is unambiguous as a type-name A.Equals(2); // Error, A is ambiguous as a simple-name } } }
N1
包含類型成員A
,且包含靜態字段A
,而且C
因為N2
匯入兩者,因此參考A
為simple_name模棱兩可,而且編譯時期錯誤。end 範例
就像using_alias_directive一樣,using_namespace_directive不會為編譯單位或命名空間的基礎宣告空間貢獻任何新成員,而是只會影響其出現的編譯單位或命名空間主體。
using_namespace_directive所參考的namespace_name會以與using_alias_directive所參考namespace_or_type_name相同的方式來解析。 因此, 相同編譯單位或命名空間主體中的 using_namespace_directive不會影響彼此,而且可以依任何順序撰寫。
14.5.4 使用靜態指示詞
using_static_directive會將直接包含在類型宣告中的巢狀類型和靜態成員匯入到立即封入編譯單位或命名空間主體中,讓每個成員和型別的標識碼不具資格即可使用。
using_static_directive
: 'using' 'static' type_name ';'
;
在包含using_static_directive之編譯單位或命名空間主體的成員宣告中,可以直接參考指定型別宣告中所包含的可存取巢狀類型和靜態成員(除了擴充方法除外)。
範例:
namespace N1 { class A { public class B {} public static B M() => new B(); } } namespace N2 { using static N1.A; class C { void N() { B b = M(); } } }
在上述程式代碼中,命名空間中的
N2
成員宣告內,直接可以使用 的靜態成員和巢狀類型N1.A
,因此方法N
可以參考B
的 和M
成員N1.A
。end 範例
using_static_directive特別不會將擴充方法直接匯入為靜態方法,但讓它們可用於擴充方法調用(~12.8.9.3)。
範例:
namespace N1 { static class A { public static void M(this string s){} } } namespace N2 { using static N1.A; class B { void N() { M("A"); // Error, M unknown "B".M(); // Ok, M known as extension method N1.A.M("C"); // Ok, fully qualified } } }
using_static_directive會匯入 中包含的
N1.A
擴充方法M
,但只匯入做為擴充方法。 因此,編譯時間錯誤主體B.N
中對 的第一個參考M
會導致編譯時間錯誤,因為沒有名為M
的成員位於範圍內。end 範例
using_static_directive只會匯入直接在指定型別中宣告的成員和型別,而不是在基類中宣告的成員和型別。
範例:
namespace N1 { class A { public static void M(string s){} } class B : A { public static void M2(string s){} } } namespace N2 { using static N1.B; class C { void N() { M2("B"); // OK, calls B.M2 M("C"); // Error. M unknown } } }
using_static_directive會匯入 中包含的
N1.B
方法M2
,但不會匯入 中包含的N1.A
方法M
。 因此,在編譯時期錯誤主體中,對的C.N
參考M
會導致編譯時間錯誤,因為沒有名為M
的成員位於範圍內。 開發人員必須新增第二using static
個指示詞,以N1.A
指定 中的方法也應該匯入。end 範例
在 \14.5.3 中會討論多個using_namespace_directives與using_static_directives之間的模棱兩可。
14.6 命名空間成員宣告
namespace_member_declaration是namespace_declaration(~14.3)或type_declaration(~14.7)。
namespace_member_declaration
: namespace_declaration
| type_declaration
;
編譯單位或命名空間主體可以包含 namespace_member_declarations,這類宣告會將新的成員貢獻至包含編譯單位或命名空間主體的基礎宣告空間。
14.7 類型宣告
type_declaration是class_declaration(15.2)、struct_declaration(16.2)、interface_declaration(~18.2)、enum_declaration(~19.2)或delegate_declaration(20.2)。
type_declaration
: class_declaration
| struct_declaration
| interface_declaration
| enum_declaration
| delegate_declaration
;
type_declaration可能會以編譯單位中的最上層宣告或命名空間、類別或結構內的成員宣告的形式發生。
當型T
別的類型宣告在編譯單位中以最上層宣告的形式發生時,類型宣告的完整名稱 ({7.8.2) 與宣告的不限定名稱 ({7.8.2) 相同。 當型別的型T
別宣告發生在命名空間、類別或結構宣告內時,類型S.N
宣告的完整名稱 ({7.8.3),其中 S
是包含命名空間、類別或結構宣告的完整名稱,而 N
是宣告的不限定名稱。
在類別或結構內宣告的類型稱為巢狀類型(~15.3.9)。
允許的存取修飾詞和類型宣告的預設存取權取決於宣告發生的內容 ({7.5.2):
- 在編譯單位或命名空間中宣告的類型可以具有
public
或internal
存取權。 預設值為internal
存取權。 - 類別中宣告的類型可以有
public
、、protected internal
、protected
、private protected
、internal
或private
存取。 預設值為private
存取權。 - 結構中宣告的類型可以有
public
、internal
或private
存取。 預設值為private
存取權。
14.8 限定別名成員
14.8.1 一般
命名空間別名限定符::
可讓您保證類型名稱查閱不受新類型和成員的引進影響。 命名空間別名限定符一律會出現在兩個稱為左側和右手標識碼的標識碼之間。 不同於一般 .
限定符,限定符的 ::
左側標識符只會查閱為extern或使用別名。
qualified_alias_member提供全域命名空間的明確存取權,以及使用可能由其他實體隱藏的別名。
qualified_alias_member
: identifier '::' identifier type_argument_list?
;
qualified_alias_member可以做為namespace_or_type_name(~7.8)或member_access中的左操作數(~12.8.7)。
qualified_alias_member包含兩個標識符,稱為左側和右側標識符,由::
令牌分隔,並選擇性地後面接著type_argument_list。 當左側標識碼是全域時,就會搜尋全域命名空間來尋找右側標識符。 針對任何其他左側標識碼,該標識符會查閱為 extern 或使用別名(\14.4 和 \14.5.2)。 如果沒有這類別名或別名參考類型,就會發生編譯時期錯誤。 如果別名參考命名空間,則會搜尋該命名空間的右側標識符。
qualified_alias_member有兩種形式之一:
N::I<A₁, ..., Aₑ>
,其中N
和I
代表標識碼,而<A₁, ..., Aₑ>
是類型自變數清單。 (e
一律至少是一個。N::I
,其中N
和I
表示標識碼。 (在此情況下,e
被視為零。
使用此表示法時,qualified_alias_member的意義會依下列方式決定:
- 如果
N
是識別碼global
,則會搜尋I
全域命名空間:- 如果全域命名空間包含名為 且
e
為I
零的命名空間,則qualified_alias_member會參考該命名空間。 - 否則,如果全域命名空間包含名為
I
且e
為零的非泛型型別,則 qualified_alias_member 會參考該類型。 - 否則,如果全域命名空間包含名為
I
且具有e
型別參數的類型,則 qualified_alias_member 會參考以指定型別自變數建構的型別。 - 否則, qualified_alias_member 未定義,而且會發生編譯時間錯誤。
- 如果全域命名空間包含名為 且
- 否則,從命名空間宣告 ({14.3) 開始,會立即包含 qualified_alias_member (如果有的話),繼續進行每個封入命名空間宣告(如果有的話),並以包含 qualified_alias_member的編譯單位結尾,評估下列步驟,直到實體找到為止:
- 如果命名空間宣告或編譯單位包含 將 N 與型別建立關聯的using_alias_directive ,則 qualified_alias_member 未定義且發生編譯時間錯誤。
- 否則,如果命名空間宣告或編譯單位包含與命名空間相關聯的
N
extern_alias_directive或using_alias_directive,則:- 如果與
N
關聯的命名空間包含名為I
且e
為零的命名空間,則 qualified_alias_member 會參考該命名空間。 - 否則,如果與
N
關聯的命名空間包含名為I
的非泛型型別,且e
為零,則 qualified_alias_member 會參考該類型。 - 否則,如果與
N
關聯的命名空間包含具有類型參數的型I
e
別,則qualified_alias_member會參考以指定型別自變數建構的型別。 - 否則, qualified_alias_member 未定義,而且會發生編譯時間錯誤。
- 如果與
- 否則, qualified_alias_member 未定義,而且會發生編譯時間錯誤。
範例:在程式代碼中:
using S = System.Net.Sockets; class A { public static int x; } class C { public void F(int A, object S) { // Use global::A.x instead of A.x global::A.x += A; // Use S::Socket instead of S.Socket S::Socket s = S as S::Socket; } }
A
類別是以global::A
參考,且型System.Net.Sockets.Socket
別會使用S::Socket
參考。 使用A.x
和S.Socket
會改為造成編譯時間錯誤,因為A
和S
會解析為參數。end 範例
注意:只有在做為qualified_alias_name的左側標識符時,標識元
global
才具有特殊意義。 它不是關鍵詞,也不是別名;它是內容關鍵詞 (~6.4.4)。 在程式碼中:class A { } class C { global.A x; // Error: global is not defined global::A y; // Valid: References A in the global namespace }
using
global.A
會造成編譯時期錯誤,因為範圍中沒有名為global
的實體。 如果某些名為 global 的實體位於範圍中,則global
中的global.A
會解析為該實體。使用
global
做為qualified_alias_member的左側標識符一律會導致命名空間中的global
查閱,即使有名為global
的別名。 在程式碼中:using global = MyGlobalTypes; class A { } class C { global.A x; // Valid: References MyGlobalTypes.A global::A y; // Valid: References A in the global namespace }
global.A
解析為MyGlobalTypes.A
,並global::A
解析為全域命名空間中的 類別A
。end note
14.8.2 別名的唯一性
每個編譯單位和命名空間主體都有個別的宣告空間,用於外部別名和使用別名。 因此,雖然extern別名或使用別名的名稱在extern別名集合內必須是唯一的,而且使用在包含編譯單位或命名空間主體的中宣告的別名,只要別名只能與 ::
限定符搭配使用,別名就可以擁有與類型或命名空間相同的名稱。
範例:在下列內容中:
namespace N { public class A {} public class B {} } namespace N { using A = System.IO; class X { A.Stream s1; // Error, A is ambiguous A::Stream s2; // Ok } }
名稱
A
在第二個命名空間主體中有兩個可能的意義,因為 類別A
和using別名A
都在範圍內。 基於這個理由,A
在限定名稱A.Stream
中使用 是模棱兩可的,並會導致發生編譯時間錯誤。 不過,搭配::
限定符使用A
不是錯誤,因為A
只會查閱為命名空間別名。end 範例