成員聲明可用于控制對(duì)其的訪問(wèn)。成員可訪問(wèn)性由該成員的聲明的可訪問(wèn)性(declared accessibility,第三章第 5.1 節(jié))以及包含該成員的類型的可訪問(wèn)性(如果存在的話)來(lái)確定的。
當(dāng)允許訪問(wèn)指定成員時(shí),我們稱該成員是可訪問(wèn)的(accessible)。相反,當(dāng)不允許訪問(wèn)指定成員時(shí),我們稱該成員是不可訪問(wèn)的(inaccessible)。
當(dāng)引發(fā)訪問(wèn)的文本位于成員的可訪問(wèn)域(accessibility domain,第三章第 5.2 節(jié))內(nèi),則該成員允許被訪問(wèn)。
成員的聲明可訪問(wèn)性(declared accessibility)可為以下類型之一:
public
修飾符來(lái)選擇之,其直觀含義為「不受限制的訪問(wèn)(access not limited)」;protected
修飾符來(lái)選擇之,其直觀含義為「僅限該類及其派生類型內(nèi)可訪問(wèn)(access limited to the containing class or types derived from the containing class)」;internal
修飾符來(lái)選擇之,其直觀含義為「僅限本程序內(nèi)可訪問(wèn)(access limited to this program)」;protected
和 internal
修飾符來(lái)選擇之,其直觀含義為「僅限本程序內(nèi)或該類及其派生類性內(nèi)可訪問(wèn)(access limited to this program or types derived from the containing class)」;private
修飾符來(lái)選擇之,其直觀含義為「僅限于該類型內(nèi)部訪問(wèn)(access limited to the containing type)」。聲明成員時(shí)被允許使用的可訪問(wèn)性類型取決于該成員所處之上下文。而且當(dāng)成員在聲明時(shí)不帶任何訪問(wèn)控制修飾符(access modifiers),那么聲明所在的上下文會(huì)為其選擇一個(gè)默認(rèn)的聲明可訪問(wèn)性。
public
聲明可訪問(wèn)性。命名空間聲明不允許有訪問(wèn)控制修飾符。public
或 internal
聲明可訪問(wèn)性,且默認(rèn)的聲明可訪問(wèn)性為 internal
。private
。(注意,類中聲明一個(gè)某類型的成員也可以從五種聲明可訪問(wèn)性中挑選一個(gè),盡管這個(gè)類型作為命名空間下的成員在聲明時(shí)只有 public
或 internal
可選。)public
、internal
和 private
聲明可訪問(wèn)性,且默認(rèn)聲明可訪問(wèn)性為 private
(這是因?yàn)榻Y(jié)構(gòu)隱式密封 sealed
)。結(jié)構(gòu)成員如果是在這個(gè)結(jié)構(gòu)內(nèi)聲明的(也就是說(shuō)不是繼承自其基結(jié)構(gòu)),那么其聲明可訪問(wèn)性不可是 protected
或 protected internal
。(注意,當(dāng)一個(gè)類型聲明為某結(jié)構(gòu)的成員時(shí),可以從 public
、internal
和 private
中選擇一個(gè)聲明可訪問(wèn)性,盡管這個(gè)類型在命名空間中的聲明可訪問(wèn)性只能是 public
或 internal
的。)public
聲明可訪問(wèn)性。接口成員聲明不允許有訪問(wèn)控制修飾符。public
聲明可訪問(wèn)性。枚舉成員聲明不允許有訪問(wèn)控制修飾符。成員可訪問(wèn)域(accessibility domain)由其所在程序文本之區(qū)段(sections,不一定是連續(xù)的)所組成,于該域之內(nèi)可訪問(wèn)成員。為了定義成員的可訪問(wèn)域,若成員未被聲明于一個(gè)類型內(nèi)則謂之「頂級(jí)(top-level)」,若成員被聲明于另一個(gè)類型內(nèi)則謂之「嵌套(nested)」。此外,程序的程序文本(program text)被定義為其所有源文件中的全部文本,而類型的程序文本也被定義為其類型(及其嵌套類型)聲明中的全部文本。
預(yù)定義類型(predefined type,諸如 object
、int
或 double
)的可訪問(wèn)域是沒(méi)有限制的(unlimited)。
頂級(jí)未綁定類型 T(第四章第 4.3 節(jié))的可訪問(wèn)域被聲明在程序 P 中應(yīng)被如下定義:
public
的,則其可訪問(wèn)域是 P 的整個(gè)程序文本以及所有引用了 P 的程序;internal
的,則其可訪問(wèn)域是 P 的整個(gè)程序文本。聲明在程序 P 的類型 T 內(nèi)的嵌套成員 M 的可訪問(wèn)類型的定義,遵照以下規(guī)則(注意,M 自身可能也是一個(gè)類型):
public
,那么 M 的可訪問(wèn)域與 T 的可訪問(wèn)域一致;protected internal
,設(shè) D 為程序文本 P 與所有派生自 T 類型的程序文本(在 P 外部聲明的)的并集(union),則 M 的可訪問(wèn)域?yàn)?T 的可訪問(wèn)域與 D 的交集(intersection);protected
,設(shè) D 為 T 的程序文本與所有派生自 T 類型的程序文本的并集(union),則 M 的可訪問(wèn)域?yàn)?T 的可訪問(wèn)域與 D 的交集(intersection);internal
,則 M 的可訪問(wèn)域?yàn)?T 的可訪問(wèn)域與 P 的程序文本的交集(intersection);private
,則 M 的可訪問(wèn)域就是 T 的程序文本。由這些定義可以得知,嵌套成員的可訪問(wèn)域至少是該成員聲明所在的類型的程序文本。此外還能發(fā)現(xiàn)這么一點(diǎn),成員的可訪問(wèn)域絕不比該成員聲明所在類型的可訪問(wèn)域更廣。
直觀地說(shuō),當(dāng)訪問(wèn)類型或成員 M 時(shí),遵循以下步驟進(jìn)行計(jì)算以確保其可被訪問(wèn)到:
piblic
,則允許其被訪問(wèn);protected internal
,那么訪問(wèn)發(fā)生在 M 聲明所在的程序內(nèi)或訪問(wèn)發(fā)生在派生自 M 的類型(第三章第 5.3 節(jié))進(jìn)行訪問(wèn)時(shí),允許其被訪問(wèn);protected
,那么訪問(wèn)發(fā)生在 M 聲明所在的類內(nèi)或訪問(wèn)發(fā)生在派生自 M 的類型(第三章第 5.3 節(jié))進(jìn)行訪問(wèn)時(shí),允許其被訪問(wèn);internal
,那么訪問(wèn)發(fā)生在 M 聲明所在的程序內(nèi),允許其被訪問(wèn);private
,那么訪問(wèn)發(fā)生在 M 聲明所在的類型內(nèi),允許其被訪問(wèn);在下面這個(gè)例子中,
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;
}
}
類和成員擁有如下可訪問(wèn)域:
A
和 A.X
的可訪問(wèn)域不受限制;A.Y
、B
、B.X
、B.Y
、B.C
、B.C.X
以及 B.C.Y
的可訪問(wèn)域是程序文本所在的程序內(nèi);A.Z
的可訪問(wèn)域是 A 的程序文本;B.Z
和 B.D
的可訪問(wèn)域是 B 的程序文本,包括 B.C
和 B.D
的程序文本;B.C.Z
的可訪問(wèn)域是 B.C
的程序文本;B.D.X
和 B.D.Y
的可訪問(wèn)域是 B 的程序文本,包括 B.C
和 B.D
的程序文本;B.D.Z
的可訪問(wèn)域是 B.D
的程序文本;如示例所示,成員的可訪問(wèn)域永不會(huì)大于其所在類型(的可訪問(wèn)域)。比方說(shuō)即便成員 X 的聲明可訪問(wèn)性都是 public
,但除了 A.X
外其余成員都受制于其所在類型。
如第三章第四節(jié)所解釋的,所有來(lái)自基類的成員(除了實(shí)例構(gòu)造函數(shù)、析構(gòu)函數(shù)和靜態(tài)構(gòu)析函數(shù))由派生類型所繼承。這甚至包括了基類的私有成員。然而,所包含的私有成員的可訪問(wèn)域只能在其聲明的類型內(nèi)部的程序文本內(nèi)。比方說(shuō):
class A
{
int x;
static void F(B b) {
b.x = 1; // 正確
}
}
class B: A
{
static void F(B b) {
b.x = 1; // 錯(cuò)誤,x 不可訪問(wèn)
}
}
B 類從 A 類繼承了私有(private)成員 x
。因?yàn)檫@個(gè)成員是私有的,所以它只能在 A 的類主體內(nèi)部可被訪問(wèn)。因此,可以通過(guò) A.F
方法訪問(wèn) b.x
,但不能通過(guò) B.F
訪問(wèn) b.x
。
當(dāng)一個(gè)以 protected
修飾的實(shí)例成員被程序文本之外的類訪問(wèn)時(shí),或者當(dāng)一個(gè)以 protected internal
丟失的實(shí)例成員被程序文本之外的類訪問(wèn)時(shí),訪問(wèn)必須發(fā)生在此類的派生類內(nèi)。此外,這個(gè)訪問(wèn)必須通過(guò)在派生類實(shí)例或構(gòu)造自它的類型的實(shí)例來(lái)訪問(wèn)。這個(gè)限制(restriction)組織了一個(gè)派生類訪問(wèn)另一個(gè)派生類的 protected
成員(即使它們派生自同一個(gè)基類)。
假設(shè) B 為基類(它聲明了一個(gè)受保護(hù)的(protected)實(shí)例成員 M),并設(shè) B 為其派生類。在 D 的類主體(class-body)內(nèi)部,須按照以下形式之一訪問(wèn) M:
M
形式的非限定(unqualified)的 type-name
或 primary-expression
;E.M
形式的 primary-expression
,假設(shè)類型 E 為 T 或其派生類,T 為 類型 D 或構(gòu)造自 D 的類型;base.M
形式的 primary-expression
除這些形式的訪問(wèn)外,派生類可以在構(gòu)造初始化器(constructor-initializer,第十章第 11.1 節(jié))內(nèi)訪問(wèn)到受保護(hù)的(protected)基類實(shí)例構(gòu)造函數(shù)
public class A
{
protected int x;
static void F(A a, B b) {
a.x = 1; // 正確
b.x = 1; // 正確
}
}
public class B: A
{
static void F(A a, B b) {
a.x = 1; // 錯(cuò)誤,必須通過(guò) B 的實(shí)例訪問(wèn)
b.x = 1; // 正確
}
}
上例 A 中,可以通過(guò) A 和 B 訪問(wèn)到 x,因?yàn)檫@兩次訪問(wèn)都發(fā)生在 A 的實(shí)例或其派生類中。然而,在 B 中,不能通過(guò) A 的實(shí)例去訪問(wèn) x,因?yàn)?A 不是 B 的派生類。
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";
}
}
上例中的三個(gè)對(duì) x 的賦值動(dòng)作都是合法的,因?yàn)樗鼈兌纪ㄟ^(guò)構(gòu)造自泛型類型的類類型的實(shí)例進(jìn)行的。
在 C# 語(yǔ)言的一些構(gòu)造中要求類型至少與其成員或其它類型具有相同的可訪問(wèn)性(be at least as accessible as)。如果 T 的可訪問(wèn)域(accessibility domain)是 M 的可訪問(wèn)域的超集(superset),那么我們可以說(shuō)類型 T 至少擁有與成員或類型 M 相同的可訪問(wèn)性。換句話說(shuō),如果在任何 M 可被訪問(wèn)的上下文中,T 都可被訪問(wèn),那么 T 至少擁有 M 的可訪問(wèn)性。
有以下這些可訪問(wèn)性約束:
在下例中,
class A {...}
public class B: A {...}
B 類將出現(xiàn)「編譯時(shí)錯(cuò)誤」,因?yàn)?A 類不具備至少與 B 類相同的可訪問(wèn)性。同樣,在下例中,
class A {...}
public class B
{
A F() {...}
internal A G() {...}
public A H() {...}
}
H 方法將出現(xiàn)「編譯時(shí)錯(cuò)誤」,因?yàn)?H 方法所返回的類型 A 不具備至少與該方法相同的可訪問(wèn)性。
更多建議: