第五章 不完全類型 5.1 不完全聲明 在定義一個分為多個部分的類型時,要使用一個新的類型修飾符——partial。為了保證和現有代碼的兼容性,這個標識符和其他標識符不同:與get和set相同,它不是一個關鍵字,而且它必須直接出現在關鍵字class、struct和interface之一的前面。 class-declaration: attributesopt class-modifiersopt partialopt class identifier type-parameter-listopt class-baseopt type-parameter-constraints-clausesopt class-body ;opt struct-declaration: attributesopt struct-modifiersopt partialopt struct identifier type-parameter-listopt struct-interfacesopt type-parameter-constraints-clausesopt struct-body ;opt interface-declaration: attributesopt interface-modifiersopt partialopt interface identifier type-parameter-listopt interface-baseopt type-parameter-constraints-clausesopt interface-body ;opt 類聲明: 特性可選 類修飾符可選 partial可選 class 標識符 類型參數列表可選 基類可選 類型參數約束條款可選 類體 ;可選 結構聲明: 特性可選 結構修飾符可選 partial可選 struct 標識符 類型參數列表可選 結構接口可選 類型參數約束條款可選 結構體 ;可選 接口聲明: 特性可選 接口修飾符可選 partial可選 interface 標識符 類型參數列表可選 基接口可選 類型參數約束條款可選 接口體 ;可選 不完全類型聲明中的每一部分必須包含partial修飾符,并且必須和其他部分位于相同的命名空間中。partial修飾符表明在其他位置可能有該類型聲明的附加部分,但這些附加部分不是必須的,這就運行一個單獨的類型聲明包含partial修飾符。 不完全類型的所有部分必須放在一起編譯,這才能使這些部分在編譯期間合并。但是部分類型不允許擴展已經編譯過的類型。 嵌套類型可以通過使用partial修飾符聲明為多個部分。典型的情況是,包含嵌套類型的類型的聲明也使用了partial,而潛逃類型的各個部分分別聲明在這個包含類型的各個不同部分中。 The partial modifier is not permitted on delegate or enum declarations. partial修飾符不允許用于委托或枚舉聲明。 5.1.1 特性(Attribute) 不完全類型的各個部分上的特性將被按照不確定的順序合并,如果一個特性被放在多個部分上,在相當于在類型上對一個特性使用了多次。例如,下面的兩部分: [Attr1, Attr2("hello")] partial class A {} [Attr3, Attr2("goodbye")] partial class A {} 相當于下面的聲明: [Attr1, Attr2("hello"), Attr3, Attr2("goodbye")] class A {} 類型參數上的特性按照同樣的方式合并。 5.1.2 修飾符 當一個不完全類型聲明中包含可訪問性說明(public、protected、internal和private修飾符)時,所有其它部分都可以包含一個同樣的修飾符。如果不完全類型的任何一個部分都不包含可訪問性說明,這個類型將具有默認的恰當的可訪問性。 如果嵌套類型的不完全聲明中包含new修飾符,在這個嵌套類型隱藏了繼承的成員時將不會出現警告。 如果類的不完全聲明中的一個或多個部分包含了abstract修飾符,則這個類被認為是抽象的。否則,這個類被認為是非抽象的。 如果類的不完全聲明中的一個或多個部分包含了sealed修飾符,則這個類被認為是密封的。否則,這個類被認為是非密封的。 注意一個類不能既是抽象的又是密封的。 當在不完全類型聲明的一個部分上使用了unsafe修飾符,則只有這一個特定的部分被認為是在不安全環境中。 5.1.3 類型參數和約束 如果一個分型類型被聲明在多個部分中,每個部分都必須聲明類型參數。各個部分必須具有相同數量的類型參數,每個類型參數的名稱和順序也必須一樣。 若一個不完全泛型類型包含類型參數約束(where子句),則其它部分中也可以包含同樣的約束。不過每個包含約束的部分必須對相同的類型參數的集合進行約束,這個集合中的每個類型參數的類、接口和構造器約束必須相同。如果不完全泛型類型的每個部分均未指定類型參數約束,則這些類型參數被認為是不受約束的。 下面的例子 partial class Dictionary<K,V> where K: IComparable<K> where V: IKeyProvider<K>, IPersistable { ... } partial class Dictionary<K,V> where V: IPersistable, IKeyProvider<K> where K: IComparable<K> { ... } partial class Dictionary<K,V> { ... } 是正確的,因為包含約束的部分(第一個和第二個)分別有效地對同一組類型參數指定了相同的一組類、接口和構造器約束。 5.1.4 基類 當一個不完全類聲明中包含指定基類時,允許各個部分包含同樣的指定基類。如果一個不完全類型的任何部分都未指定基類,則該類的基類為System.Object。 5.1.5 基接口 分別聲明在不同部分中的基接口是指定在各個部分上的基接口的聯合。一個特定的基接口在每個部分上只能命名一次,但允許在多個部分上命名同一個接口。基接口中的任何成員只能實現一次。 In the example 在下面的例子中 partial class C: IA, IB {...} partial class C: IC {...} partial class C: IA, IB {...} C類的基接口集合是IA、IB和IC。 通常,一個部分只為該部分上聲明的接口提供一個實現,然而,這不是必須的。一個部分可以為另一個不同的部分上聲明的接口提供實現: partial class X { int IComparable.CompareTo(object o) {...} } partial class X: IComparable { ... } 5.1.6 成員 在多個部分中聲明的成員只是每個部分中聲明的成員的簡單聚合。類型聲明的所有部分中的類體共享相同的聲明空間,并且每個成員的作用域都貫穿所有的部分。任何成員的可訪問性總是包含了封閉類型的所有部分;在某一部分中聲明的private成員可以在另一部分中自由地訪問。如果在多個部分中聲明了相同的成員則會產生編譯錯誤,除非這個成員是一個用partial修飾符聲明的類型。 partial class A { int x; // 錯誤,不能多次聲明x partial class Inner // 正確,這是一個不完全內部類型 { int y; } } partial class A { int x; // 錯誤,不能多次聲明x partial class Inner // 正確,這是一個不完全內部類型 { int z; } } 盡管成員的順序對于C#代碼來說并不重要,但對于和其它語言或環境進行接口連接這可能是重要的。在這種情況下,在類型的多個部分中聲明的成員的順序是未定義的。 5.2 名字綁定 盡管可擴展的類型的各個部分必須聲明在相同的命名空間中,但各個部分中可以寫入不同的命名空間聲明。因此,不同的using指令可以出現在各個部分中。當在一個部分中解釋簡單名字時,僅考慮該部分中聲明的命名空間中的using指令。 namespace N { using List = System.Collections.ArrayList; partial class A { List x; // x的類型是System.Collections.ArrayList } } namespace N { using List = Widgets.LinkedList; partial class A { List y; // y的類型是Widgets.LinkedList }
|