深刻淺出OOP(五): C#訪問修飾符(Public/Private/Protected/Internal/Sealed/Constants)html
訪問修飾符(或者叫訪問控制符)是面嚮對象語言的特性之一,用於對類、類成員函數、類成員變量進行訪問控制。同時,訪問控制符也是語法保留關鍵字,用於封裝組件。less
在建立類時,咱們須要考慮類的做用域範圍,如誰可訪問該類,誰可訪問該類成員變量,誰可訪問該類成員函數。 換而言之,咱們須要約束類成員的訪問範圍。一個簡單的規則,類成員函數、類成員變量之間能夠自由函數
訪問不受約束,這裏主要說的是外部的訪問約束。在建立class的時候,默認的訪問控制符爲private。編碼
下面作個小實驗,打開Visual Studio,建立一個C#的Console應用,命名爲AccessModifiers。 添加一個類,命名爲
luaModifiers ,拷貝以下代碼:
1: System;
2:
3: AccessModifiers
4: {
5: Modifiers
6: {
7: AAA()
8: {
9: Console.WriteLine("");
10: }
11:
12: BBB()
13: {
14: Console.WriteLine("");
15: AAA();
16: }
17: }
18:
19: Program
20: {
21: Main([] args)
22: {
23: Modifiers.BBB();
24: }
25: }
26: }
上面的代碼建立了一個類Modifiers,它有2個static函數:AAA、BBB。其中BBB是public訪問修飾符,在Main中調用BBB結果以下:spa
Modifiers BBBcode
Modifiers AAAhtm
BBB被標記爲public,既任何函數皆可訪問和運行。AAA被標記爲private,既AAA僅能被其類內函數訪問,外包是沒法訪問的。對象
修改代碼以下:blog
1: Program
2: {
3: Main([] args)
4: {
5: Modifiers.AAA();
6: Console.ReadKey();
7: }
8: }
則運行報錯:
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
下面咱們對AAA進行重構,修改以下:
1: Modifiers
2: {
3: AAA()
4: {
5: Console.WriteLine("");
6: }
7:
8: BBB()
9: {
10: Console.WriteLine("");
11: AAA();
12: }
13: }
14:
15: Program
16: {
17: Main([] args)
18: {
19: Modifiers.AAA();
20: Console.ReadKey();
21: }
22: }
運行結果:
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
既,protected修飾符的成員變量,僅能被其同類、子類訪問,外部沒法訪問。
咱們接着添加子類,來擴展這個實例:
1: ModifiersBase
2: {
3: AAA()
4: {
5: Console.WriteLine("");
6: }
7: BBB()
8: {
9: Console.WriteLine("");
10: }
11: CCC()
12: {
13: Console.WriteLine("");
14: }
15: }
16:
17: ModifiersDerived:ModifiersBase
18: {
19: XXX()
20: {
21: AAA();
22: BBB();
23: CCC();
24: }
25: }
26:
27: Program
28: {
29: Main([] args)
30: {
31: ModifiersDerived.XXX();
32: Console.ReadKey();
33: }
34: }
運行結果:
'AccessModifiers.ModifiersBase.AAA()' is inaccessible due to its protection level
緣由是AAA默認爲Private訪問控制符,僅可在基類中訪問,子類沒法訪問。
換另一個場景,用Visual Studio新建一個dll類庫AccessModifiersLibrary,添加一個ClassA類,標記爲iternal修飾符,代碼以下:
1: AccessModifiersLibrary.ClassA:
2:
3: AccessModifiersLibrary
4: {
5: ClassA
6: {
7: }
8: }
編譯後,會在~\AccessModifiersLibrary\bin\Debug下找到這個dll。 在Program.cs使用這個dll, 添加dll引用,添加命名空間:
1: AccessModifiersLibrary;
2:
3: AccessModifiers
4: {
5: Program
6: {
7: Main([] args)
8: {
9: ClassA classA;
10: }
11: }
12: }
編譯代碼,運行結果以下:
Compile time error: 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level
之因此報錯,是由於internal 修飾符的做用域。
internal 修飾符僅對當前程序集(dll 或 exe)內有效,所以,當class添加internal修飾符則意味着程序集外沒法訪問。
命名空間的修飾符
咱們嘗試給命名空間添加修飾符,代碼以下:
1: AccessModifiers
2: {
3: Program
4: {
5: Main([] args)
6: {
7:
8: }
9: }
10: }
運行報錯。
Compile time error: A namespace declaration cannot have modifiers or attributes
結論,咱們沒法對命名空間添加修飾符,命名空間默認是public的做用域。
修改以下代碼:
1: AccessModifiers
2: {
3: Program
4: {
5: Main([] args)
6: {
7:
8: }
9: }
10: }
編譯報錯:
Compile time error: Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal
類可被修飾爲public、internal,它沒法被標記爲protected或者private。類默認的修飾符爲internal。
重構代碼以下:
1: AccessModifiers
2: {
3: Program
4: {
5: Main([] args)
6: {
7: }
8:
9: Method1()
10: {
11:
12: }
13: }
14: }
編譯運行:
Compile time error: More than one protection modifier
結論,修飾符不支持嵌套。既每次僅能用一個修飾符。
重構代碼:
1: AccessModifiersLibrary
2: {
3: ClassA
4: {
5: MethodClassA(){}
6: }
7: }
8:
9: AccessModifiersLibrary;
10:
11: AccessModifiers
12: {
13: Program
14: {
15: Main([] args)
16: {
17: ClassA classA = ClassA();
18: classA.MethodClassA();
19: }
20: }
21: }
運行結果:
'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level The type 'AccessModifiersLibrary.ClassA' has no constructors defined 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level 'AccessModifiersLibrary.ClassA' does not contain a definition for 'MethodClassA' and no extension method 'MethodClassA' accepting a first argument of type 'AccessModifiersLibrary.ClassA' could be found (are you missing a using directive or an assembly reference?)
結論,類成員變量的訪問控制受限於其類的修飾符,如上面例子class爲internal修飾符,則該類僅能在程序集內可被訪問。
對代碼進行重構,在ClassA、ClassB、ClassC中添加以下代碼:
1: AccessModifiersLibrary
2: {
3: ClassA
4: {
5: MethodClassA()
6: {
7:
8: }
9: }
10:
11: ClassB:ClassA
12: {
13: MethodClassB()
14: {
15: MethodClassA();
16: }
17: }
18:
19: ClassC
20: {
21: MethodClassC()
22: {
23: ClassA classA= ClassA();
24: classA.MethodClassA();
25: }
26: }
27: }
28:
29: AccessModifiersLibrary;
30:
31: AccessModifiers
32: {
33: Program
34: {
35: Main([] args)
36: {
37: ClassC classC= ClassC();
38: classC.MethodClassC();
39: }
40: }
41: }
運行結果無錯誤。
結論:Protected internal 修飾符作了2件事情,protected約定類類和繼承類訪問控制,internal約定了只能在當前程序集中。
1: AccessModifiers
2: {
3: AAA
4: {
5: a;
6: MethodAAA(AAA aaa,BBB bbb)
7: {
8: aaa.a = 100;
9: bbb.a = 200;
10: }
11: }
12: BBB:AAA
13: {
14: MethodBBB(AAA aaa, BBB bbb)
15: {
16: aaa.a = 100;
17: bbb.a = 200;
18: }
19: }
20: Program
21: {
22: Main([] args)
23: {
24: }
25: }
26: }
編譯結果:
Cannot access protected member 'AccessModifiers.AAA.a' via a qualifier of type 'AccessModifiers.AAA'; the qualifier must be of type 'AccessModifiers.BBB' (or derived from it)
結論:AAA中定義了一個a的protected變量,其僅能在本身內部訪問和繼承其的子類內訪問。可是,經過傳參方式傳入的則沒法訪問--這裏要求是public權限。
看代碼:
1: AccessModifiers
2: {
3: AAA
4: {
5:
6: }
7: BBB:AAA
8: {
9:
10: }
11: Program
12: {
13: Main([] args)
14: {
15: }
16: }
17: }
編譯報錯:
Compile time error: Inconsistent accessibility: base class 'AccessModifiers.AAA' is less accessible than class 'AccessModifiers.BBB'
子類不能比其基類的訪問控制符做用域範圍大,如上面的例子中,基類爲internal,而子類爲public則報錯了。
去掉繼承,代碼重構爲以下結果:
1: AccessModifiers
2: {
3: AAA
4: {
5:
6: }
7: BBB
8: {
9: AAA MethodB()
10: {
11: AAA aaa= AAA();
12: aaa;
13: }
14: }
15: Program
16: {
17: Main([] args)
18: {
19: }
20: }
21: }
編譯結果:
Inconsistent accessibility: return type 'AccessModifiers.AAA' is less accessible than method 'AccessModifiers.BBB.MethodB()'
這樣也編譯不經過,由於AAA爲internal的訪問類型,在public BBB中返回了public的AAA,則意味着在其餘程序集中也可能訪問AAA,這樣是違法了internal修飾符原則,故編譯報錯。
同理,以下的代碼也是同樣的問題致使編譯報錯:
1: AccessModifiers
2: {
3: AAA
4: {
5:
6: }
7: BBB
8: {
9: AAA aaa;
10: }
11: Program
12: {
13: Main([] args)
14: {
15: }
16: }
17: }
如對代碼作重構,去掉BBB中AAA變量的修飾,既默認爲private訪問修飾符,則編譯沒有錯誤了。
1: AccessModifiers
2: {
3: AAA
4: {
5:
6: }
7: BBB
8: {
9: AAA a;
10: }
11: Program
12: {
13: Main([] args)
14: {
15: }
16: }
17: }
參考MSDN中修飾符說明:
同一程序集中的任何其餘代碼或引用該程序集的其餘程序集均可以訪問該類型或成員。
只有同一類或結構中的代碼能夠訪問該類型或成員。
只有同一類或結構或者此類的派生類中的代碼才能夠訪問的類型或成員。
同一程序集中的任何代碼均可以訪問該類型或成員,但其餘程序集中的代碼不能夠。
protected internal
由其聲明的程序集或另外一個程序集派生的類中任何代碼均可訪問的類型或成員。 從另外一個程序集進行訪問必須在類聲明中發生,該類聲明派生自其中聲明受保護的內部元素的類,而且必須經過派生的類類型的實例發生。
同時,C#中類、枚舉、結構體等修飾符規則表以下:
Sealed修飾符的類,不可被其餘類繼承。
1: AccessModifiers
2: {
3: AAA
4: {
5:
6: }
7: BBB:AAA
8: {
9:
10: }
11: Program
12: {
13: Main([] args)
14: {
15: }
16: }
17: }
運行報錯:
'AccessModifiers.BBB': cannot derive from sealed type 'AccessModifiers.AAA'
Sealed類使用以下:
1: System;
2:
3: AccessModifiers
4: {
5: AAA
6: {
7: x = 100;
8: MethodA()
9: {
10: Console.WriteLine("");
11: }
12: }
13: Program
14: {
15: Main([] args)
16: {
17: AAA aaa= AAA();
18: Console.WriteLine(aaa.x);
19: aaa.MethodA();
20: Console.ReadKey();
21: }
22: }
23: }
運行正常。
1: Program
2: {
3: x = 100;
4: Main([] args)
5: {
6: Console.WriteLine(x);
7: Console.ReadKey();
8: }
9: }
運行結果:
100
結論,Const變量在初始化的時候設定了初始值,可被使用,但不可修改值。同時const變量支持互相引用運算。
1: System;
2:
3: AccessModifiers
4: {
5: Program
6: {
7: x = y + 100;
8: y = z - 10;
9: z = 300;
10:
11: Main([] args)
12: {
13: System.Console.WriteLine("",x,y,z);
14: Console.ReadKey();
15: }
16: }
17: }
可是請不要循環依賴,不然編譯器會檢測報錯:
1: System;
2:
3: AccessModifiers
4: {
5: Program
6: {
7: x = y + 100;
8: y = z - 10;
9: z = x;
10:
11: Main([] args)
12: {
13: System.Console.WriteLine("",x,y,z);
14: Console.ReadKey();
15: }
16: }
17: }
檢測報錯:
The evaluation of the constant value for 'AccessModifiers.Program.x' involves a circular definition
Class成員的默認修飾符爲private
class 被標記爲internal僅能被當前程序集訪問
.
Namespace默認爲public修飾符,且不能添加修飾符。
class能夠使用public 或
internal修飾符
.不能使用修飾符 protected
、 private
. class默認的修飾符爲internal
.
類成員可以使用全部修飾符,默認爲 private
.
Protected internal修飾符約定了僅在繼承類內有效
.
在public 與
internal修飾符之間,
public一般有更大的訪問權限
.
基類必須必子類有更大的修飾符訪問權限,纔可被子類繼承.
函數返回值的修飾符要有能訪問返回值的權限.
sealed Class沒法被子類繼承
.
const變量,須要在聲明時完成初始化,在編碼階段不能初始化
.
類的const變量,能夠彼此引用,可是不能造成循環引用.
const變量在編譯器進行初始化,故const的運算可被執行
.
const變量不能被標記爲
static
.
Static 變量在類首次被加載時候初始化
. int類型默認初始化爲0,bool被初始化爲False
.
static readonly 字段沒法被賦值,
static構造函數或者變量初始化時刻除外
.
文章目錄: