您好,登錄后才能下訂單哦!
訪問修飾符(或者叫訪問控制符)是面向對象語言的特性之一,用于對類、類成員函數、類成員變量進行訪問控制。同時,訪問控制符也是語法保留關鍵字,用于封裝組件。
在創建類時,我們需要考慮類的作用域范圍,如誰可訪問該類,誰可訪問該類成員變量,誰可訪問該類成員函數。 換而言之,我們需要約束類成員的訪問范圍。一個簡單的規則,類成員函數、類成員變量之間可以自由
訪問不受約束,這里主要說的是外部的訪問約束。在創建class的時候,默認的訪問控制符為private。
下面做個小實驗,打開Visual Studio,創建一個C#的Console應用,命名為AccessModifiers。 添加一個類,命名為
Modifiers ,拷貝如下代碼:
1: using System;
2:
3: namespace AccessModifiers
4: {
5: class Modifiers
6: {
7: static void AAA()
8: {
9: Console.WriteLine("Modifiers AAA");
10: }
11:
12: public static void BBB()
13: {
14: Console.WriteLine("Modifiers BBB");
15: AAA();
16: }
17: }
18:
19: class Program
20: {
21: static void Main(string[] args)
22: {
23: Modifiers.BBB();
24: }
25: }
26: }
上面的代碼創建了一個類Modifiers,它有2個static函數:AAA、BBB。其中BBB是public訪問修飾符,在Main中調用BBB結果如下:
Modifiers BBB
Modifiers AAA
BBB被標記為public,既任何函數皆可訪問和運行。AAA被標記為private,既AAA僅能被其類內函數訪問,外包是無法訪問的。
修改代碼如下:
1: class Program
2: {
3: static void Main(string[] args)
4: {
5: Modifiers.AAA();
6: Console.ReadKey();
7: }
8: }
則運行報錯:
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
下面我們對AAA進行重構,修改如下:
1: class Modifiers
2: {
3: protected static void AAA()
4: {
5: Console.WriteLine("Modifiers AAA");
6: }
7:
8: public static void BBB()
9: {
10: Console.WriteLine("Modifiers BBB");
11: AAA();
12: }
13: }
14:
15: class Program
16: {
17: static void Main(string[] args)
18: {
19: Modifiers.AAA();
20: Console.ReadKey();
21: }
22: }
運行結果:
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
既,protected修飾符的成員變量,僅能被其同類、子類訪問,外部無法訪問。
我們接著添加子類,來擴展這個實例:
1: class ModifiersBase
2: {
3: static void AAA()
4: {
5: Console.WriteLine("ModifiersBase AAA");
6: }
7: public static void BBB()
8: {
9: Console.WriteLine("ModifiersBase BBB");
10: }
11: protected static void CCC()
12: {
13: Console.WriteLine("ModifiersBase CCC");
14: }
15: }
16:
17: class ModifiersDerived:ModifiersBase
18: {
19: public static void XXX()
20: {
21: AAA();
22: BBB();
23: CCC();
24: }
25: }
26:
27: class Program
28: {
29: static void Main(string[] 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: namespace AccessModifiersLibrary
4: {
5: internal class ClassA
6: {
7: }
8: }
編譯后,會在~\AccessModifiersLibrary\bin\Debug下找到這個dll。 在Program.cs使用這個dll, 添加dll引用,添加命名空間:
1: using AccessModifiersLibrary;
2:
3: namespace AccessModifiers
4: {
5: class Program
6: {
7: static void Main(string[] 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: public namespace AccessModifiers
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7:
8: }
9: }
10: }
運行報錯。
Compile time error: A namespace declaration cannot have modifiers or attributes
結論,我們無法對命名空間添加修飾符,命名空間默認是public的作用域。
修改如下代碼:
1: namespace AccessModifiers
2: {
3: private class Program
4: {
5: static void Main(string[] 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: namespace AccessModifiers
2: {
3: public class Program
4: {
5: static void Main(string[] args)
6: {
7: }
8:
9: public private void Method1()
10: {
11:
12: }
13: }
14: }
編譯運行:
Compile time error: More than one protection modifier
結論,修飾符不支持嵌套。既每次僅能用一個修飾符。
重構代碼:
1: namespace AccessModifiersLibrary
2: {
3: internal class ClassA
4: {
5: public void MethodClassA(){}
6: }
7: }
8:
9: using AccessModifiersLibrary;
10:
11: namespace AccessModifiers
12: {
13: public class Program
14: {
15: public static void Main(string[] args)
16: {
17: ClassA classA = new 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: namespace AccessModifiersLibrary
2: {
3: public class ClassA
4: {
5: protected internal void MethodClassA()
6: {
7:
8: }
9: }
10:
11: public class ClassB:ClassA
12: {
13: protected internal void MethodClassB()
14: {
15: MethodClassA();
16: }
17: }
18:
19: public class ClassC
20: {
21: public void MethodClassC()
22: {
23: ClassA classA=new ClassA();
24: classA.MethodClassA();
25: }
26: }
27: }
28:
29: using AccessModifiersLibrary;
30:
31: namespace AccessModifiers
32: {
33: public class Program
34: {
35: public static void Main(string[] args)
36: {
37: ClassC classC=new ClassC();
38: classC.MethodClassC();
39: }
40: }
41: }
運行結果無錯誤。
結論:Protected internal 修飾符做了2件事情,protected約定類類和繼承類訪問控制,internal約定了只能在當前程序集中。
1: namespace AccessModifiers
2: {
3: class AAA
4: {
5: protected int a;
6: void MethodAAA(AAA aaa,BBB bbb)
7: {
8: aaa.a = 100;
9: bbb.a = 200;
10: }
11: }
12: class BBB:AAA
13: {
14: void MethodBBB(AAA aaa, BBB bbb)
15: {
16: aaa.a = 100;
17: bbb.a = 200;
18: }
19: }
20: public class Program
21: {
22: public static void Main(string[] 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: namespace AccessModifiers
2: {
3: class AAA
4: {
5:
6: }
7: public class BBB:AAA
8: {
9:
10: }
11: public class Program
12: {
13: public static void Main(string[] args)
14: {
15: }
16: }
17: }
編譯報錯:
Compile time error: Inconsistent accessibility: base class 'AccessModifiers.AAA' is less accessible than class 'AccessModifiers.BBB'
子類不能比其基類的訪問控制符作用域范圍大,如上面的例子中,基類為internal,而子類為public則報錯了。
去掉繼承,代碼重構為如下結果:
1: namespace AccessModifiers
2: {
3: class AAA
4: {
5:
6: }
7: public class BBB
8: {
9: public AAA MethodB()
10: {
11: AAA aaa= new AAA();
12: return aaa;
13: }
14: }
15: public class Program
16: {
17: public static void Main(string[] 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: namespace AccessModifiers
2: {
3: class AAA
4: {
5:
6: }
7: public class BBB
8: {
9: public AAA aaa;
10: }
11: public class Program
12: {
13: public static void Main(string[] args)
14: {
15: }
16: }
17: }
如對代碼做重構,去掉BBB中AAA變量的修飾,既默認為private訪問修飾符,則編譯沒有錯誤了。
1: namespace AccessModifiers
2: {
3: class AAA
4: {
5:
6: }
7: public class BBB
8: {
9: AAA a;
10: }
11: public class Program
12: {
13: public static void Main(string[] args)
14: {
15: }
16: }
17: }
參考MSDN中修飾符說明:
public
同一程序集中的任何其他代碼或引用該程序集的其他程序集都可以訪問該類型或成員。
private
只有同一類或結構中的代碼可以訪問該類型或成員。
protected
只有同一類或結構或者此類的派生類中的代碼才可以訪問的類型或成員。
internal
同一程序集中的任何代碼都可以訪問該類型或成員,但其他程序集中的代碼不可以。
protected internal
由其聲明的程序集或另一個程序集派生的類中任何代碼都可訪問的類型或成員。 從另一個程序集進行訪問必須在類聲明中發生,該類聲明派生自其中聲明受保護的內部元素的類,并且必須通過派生的類類型的實例發生。
同時,C#中類、枚舉、結構體等修飾符規則表如下:
Sealed修飾符的類,不可被其他類繼承。
1: namespace AccessModifiers
2: {
3: sealed class AAA
4: {
5:
6: }
7: class BBB:AAA
8: {
9:
10: }
11: public class Program
12: {
13: public static void Main(string[] args)
14: {
15: }
16: }
17: }
運行報錯:
'AccessModifiers.BBB': cannot derive from sealed type 'AccessModifiers.AAA'
Sealed類使用如下:
1: using System;
2:
3: namespace AccessModifiers
4: {
5: sealed class AAA
6: {
7: public int x = 100;
8: public void MethodA()
9: {
10: Console.WriteLine("Method A in sealed class");
11: }
12: }
13: public class Program
14: {
15: public static void Main(string[] args)
16: {
17: AAA aaa=new AAA();
18: Console.WriteLine(aaa.x);
19: aaa.MethodA();
20: Console.ReadKey();
21: }
22: }
23: }
運行正常。
1: public class Program
2: {
3: private const int x = 100;
4: public static void Main(string[] args)
5: {
6: Console.WriteLine(x);
7: Console.ReadKey();
8: }
9: }
運行結果:
100
結論,Const變量在初始化的時候設定了初始值,可被使用,但不可修改值。同時const變量支持互相引用運算。
1: using System;
2:
3: namespace AccessModifiers
4: {
5: public class Program
6: {
7: private const int x = y + 100;
8: private const int y = z - 10;
9: private const int z = 300;
10:
11: public static void Main(string[] args)
12: {
13: System.Console.WriteLine("{0} {1} {2}",x,y,z);
14: Console.ReadKey();
15: }
16: }
17: }
但是請不要循環依賴,否則編譯器會檢測報錯:
1: using System;
2:
3: namespace AccessModifiers
4: {
5: public class Program
6: {
7: private const int x = y + 100;
8: private const int y = z - 10;
9: private const int z = x;
10:
11: public static void Main(string[] args)
12: {
13: System.Console.WriteLine("{0} {1} {2}",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構造函數或者變量初始化時刻除外
.
參考原文:Diving into OOP (Day 5): All About C# Access Modifiers (Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields)
文章目錄:
深入淺出OOP(一): 多態和繼承(早期綁定/編譯時多態)
深入淺出OOP(二): 多態和繼承(繼承)
深入淺出OOP(三): 多態和繼承(動態綁定/運行時多態)
深入淺出OOP(四): 多態和繼承(抽象類)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。