深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)
訪問修飾符(或者叫訪問控制符)是面向?qū)ο笳Z言的特性之一,用于對(duì)類、類成員函數(shù)、類成員變量進(jìn)行訪問控制。同時(shí),訪問控制符也是語法保留關(guān)鍵字,用于封裝組件。
Public, Private, Protected at Class Level
在創(chuàng)建類時(shí),我們需要考慮類的作用域范圍,如誰可訪問該類,誰可訪問該類成員變量,誰可訪問該類成員函數(shù)。 換而言之,我們需要約束類成員的訪問范圍。一個(gè)簡單的規(guī)則,類成員函數(shù)、類成員變量之間可以自由
訪問不受約束,這里主要說的是外部的訪問約束。在創(chuàng)建class的時(shí)候,默認(rèn)的訪問控制符為private。
下面做個(gè)小實(shí)驗(yàn),打開Visual Studio,創(chuàng)建一個(gè)C#的Console應(yīng)用,命名為AccessModifiers。 添加一個(gè)類,命名為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: }?
上面的代碼創(chuàng)建了一個(gè)類Modifiers,它有2個(gè)static函數(shù):AAA、BBB。其中BBB是public訪問修飾符,在Main中調(diào)用BBB結(jié)果如下:
Modifiers BBB
Modifiers AAA
BBB被標(biāo)記為public,既任何函數(shù)皆可訪問和運(yùn)行。AAA被標(biāo)記為private,既AAA僅能被其類內(nèi)函數(shù)訪問,外包是無法訪問的。
?
修改代碼如下:
1: class Program 2: { 3: static void Main(string[] args) 4: { 5: Modifiers.AAA(); 6: Console.ReadKey(); 7: } 8: }?
則運(yùn)行報(bào)錯(cuò):
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
?
Modifiers
下面我們對(duì)AAA進(jìn)行重構(gòu),修改如下:
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: }?
運(yùn)行結(jié)果:
'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level
既,protected修飾符的成員變量,僅能被其同類、子類訪問,外部無法訪問。
?
繼承修改
我們接著添加子類,來擴(kuò)展這個(gè)實(shí)例:
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: }?
運(yùn)行結(jié)果:
'AccessModifiers.ModifiersBase.AAA()' is inaccessible due to its protection level
原因是AAA默認(rèn)為Private訪問控制符,僅可在基類中訪問,子類無法訪問。
?
類級(jí)別的Internal 修飾符
換另外一個(gè)場(chǎng)景,用Visual Studio新建一個(gè)dll類庫AccessModifiersLibrary,添加一個(gè)ClassA類,標(biāo)記為iternal修飾符,代碼如下:
1: AccessModifiersLibrary.ClassA: 2: 3: namespace AccessModifiersLibrary 4: { 5: internal class ClassA 6: { 7: } 8: }?
編譯后,會(huì)在~\AccessModifiersLibrary\bin\Debug下找到這個(gè)dll。 在Program.cs使用這個(gè)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: }編譯代碼,運(yùn)行結(jié)果如下:
Compile time error: 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level
之所以報(bào)錯(cuò),是因?yàn)閕nternal 修飾符的作用域。internal 修飾符僅對(duì)當(dāng)前程序集(dll 或 exe)內(nèi)有效,因此,當(dāng)class添加internal修飾符則意味著程序集外無法訪問。
?
?
命名空間的修飾符
?
我們嘗試給命名空間添加修飾符,代碼如下:
1: public namespace AccessModifiers 2: { 3: class Program 4: { 5: static void Main(string[] args) 6: { 7: 8: } 9: } 10: }運(yùn)行報(bào)錯(cuò)。
Compile time error: A namespace declaration cannot have modifiers or attributes
結(jié)論,我們無法對(duì)命名空間添加修飾符,命名空間默認(rèn)是public的作用域。
?
私有類
修改如下代碼:
1: namespace AccessModifiers 2: { 3: private class Program 4: { 5: static void Main(string[] args) 6: { 7: 8: } 9: } 10: }?
編譯報(bào)錯(cuò):
Compile time error: Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal
類可被修飾為public、internal,它無法被標(biāo)記為protected或者private。類默認(rèn)的修飾符為internal。
重構(gòu)代碼如下:
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: }?
編譯運(yùn)行:
Compile time error: More than one protection modifier
結(jié)論,修飾符不支持嵌套。既每次僅能用一個(gè)修飾符。
?
Internal 類和Public成員函數(shù)
重構(gòu)代碼:
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: }?
運(yùn)行結(jié)果:
'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?)
結(jié)論,類成員變量的訪問控制受限于其類的修飾符,如上面例子class為internal修飾符,則該類僅能在程序集內(nèi)可被訪問。
?
Protected Internal
對(duì)代碼進(jìn)行重構(gòu),在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: }?
運(yùn)行結(jié)果無錯(cuò)誤。
?
結(jié)論:Protected internal 修飾符做了2件事情,protected約定類類和繼承類訪問控制,internal約定了只能在當(dāng)前程序集中。
?
Protected 類成員變量
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: }?
編譯結(jié)果:
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)
結(jié)論:AAA中定義了一個(gè)a的protected變量,其僅能在自己內(nèi)部訪問和繼承其的子類內(nèi)訪問。但是,通過傳參方式傳入的則無法訪問--這里要求是public權(quán)限。
?
繼承中訪問優(yōu)先級(jí)
看代碼:
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: }?
編譯報(bào)錯(cuò):
Compile time error: Inconsistent accessibility: base class 'AccessModifiers.AAA' is less accessible than class 'AccessModifiers.BBB'
子類不能比其基類的訪問控制符作用域范圍大,如上面的例子中,基類為internal,而子類為public則報(bào)錯(cuò)了。
去掉繼承,代碼重構(gòu)為如下結(jié)果:
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: }?
編譯結(jié)果:
Inconsistent accessibility: return type 'AccessModifiers.AAA' is less accessible than method 'AccessModifiers.BBB.MethodB()'
這樣也編譯不通過,因?yàn)锳AA為internal的訪問類型,在public BBB中返回了public的AAA,則意味著在其他程序集中也可能訪問AAA,這樣是違法了internal修飾符原則,故編譯報(bào)錯(cuò)。
同理,如下的代碼也是一樣的問題導(dǎo)致編譯報(bào)錯(cuò):
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: }?
如對(duì)代碼做重構(gòu),去掉BBB中AAA變量的修飾,既默認(rèn)為private訪問修飾符,則編譯沒有錯(cuò)誤了。
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
只有同一類或結(jié)構(gòu)中的代碼可以訪問該類型或成員。
protected
只有同一類或結(jié)構(gòu)或者此類的派生類中的代碼才可以訪問的類型或成員。
internal
同一程序集中的任何代碼都可以訪問該類型或成員,但其他程序集中的代碼不可以。
protected internal
由其聲明的程序集或另一個(gè)程序集派生的類中任何代碼都可訪問的類型或成員。 從另一個(gè)程序集進(jìn)行訪問必須在類聲明中發(fā)生,該類聲明派生自其中聲明受保護(hù)的內(nèi)部元素的類,并且必須通過派生的類類型的實(shí)例發(fā)生。
?
同時(shí),C#中類、枚舉、結(jié)構(gòu)體等修飾符規(guī)則表如下:
?
?
Sealed Classes
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: }?
運(yùn)行報(bào)錯(cuò):
'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: }?
運(yùn)行正常。
?
Constants
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: }?
運(yùn)行結(jié)果:
100
結(jié)論,Const變量在初始化的時(shí)候設(shè)定了初始值,可被使用,但不可修改值。同時(shí)const變量支持互相引用運(yùn)算。
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: }?
但是請(qǐng)不要循環(huán)依賴,否則編譯器會(huì)檢測(cè)報(bào)錯(cuò):
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: }檢測(cè)報(bào)錯(cuò):
The evaluation of the constant value for 'AccessModifiers.Program.x' involves a circular definition
?
本篇小結(jié)
?
參考原文:Diving into OOP (Day 5): All About C# Access Modifiers (Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields)
?
文章目錄:
- 深入淺出OOP(一): 多態(tài)和繼承(早期綁定/編譯時(shí)多態(tài))
- 深入淺出OOP(二): 多態(tài)和繼承(繼承)
- 深入淺出OOP(三): 多態(tài)和繼承(動(dòng)態(tài)綁定/運(yùn)行時(shí)多態(tài))
- 深入淺出OOP(四): 多態(tài)和繼承(抽象類)
?
本文是由葡萄城技術(shù)開發(fā)團(tuán)隊(duì)發(fā)布,轉(zhuǎn)載請(qǐng)注明出處:葡萄城官網(wǎng)
from:?https://www.cnblogs.com/powertoolsteam/p/Diving-into-OOP-Day-All-About-Access-Modifiers-in.html
總結(jié)
以上是生活随笔為你收集整理的深入浅出OOP(五): C#访问修饰符(Public/Private/Protected/Internal/Sealed/Constants)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C# 索引器(Indexer)
- 下一篇: C#类中的internal成员可能是一种