溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

深入淺出OOP(五): C#訪問修飾符(Public/Private/Protected/Internal/Sealed/Constants)

發(fā)布時(shí)間:2020-07-07 02:26:02 來源:網(wǎng)絡(luò) 閱讀:1320 作者:powertoolsteam 欄目:編程語言

深入淺出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è)簡(jiǎn)單的規(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)?code>internal 修飾符的作用域。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ī)則表如下:

深入淺出OOP(五): C#訪問修飾符(Public/Private/Protected/Internal/Sealed/Constants)

 

 

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'

 

深入淺出OOP(五): C#訪問修飾符(Public/Private/Protected/Internal/Sealed/Constants)

 

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é)

  1. Class成員的默認(rèn)修飾符為private

  2. class 被標(biāo)記為internal僅能被當(dāng)前程序集訪問.

  3. Namespace默認(rèn)為public修飾符,且不能添加修飾符。

  4. class可以使用public 或 internal修飾符.不能使用修飾符 protected 、 private. class默認(rèn)的修飾符為internal.

  5. 類成員可使用所有修飾符,默認(rèn)為 private.

  6. Protected internal修飾符約定了僅在繼承類內(nèi)有效.

  7. 在public 與 internal修飾符之間,public通常有更大的訪問權(quán)限.

  8. 基類必須必子類有更大的修飾符訪問權(quán)限,才可被子類繼承.

  9. 函數(shù)返回值的修飾符要有能訪問返回值的權(quán)限.

  10. sealed Class無法被子類繼承.

  11. const變量,需要在聲明時(shí)完成初始化,在編碼階段不能初始化.

  12. 類的const變量,可以彼此引用,但是不能形成循環(huán)引用.

  13. const變量在編譯器進(jìn)行初始化,故const的運(yùn)算可被執(zhí)行.

  14. const變量不能被標(biāo)記為static.

  15. Static 變量在類首次被加載時(shí)候初始化. int類型默認(rèn)初始化為0,bool被初始化為False.

  16. static readonly 字段無法被賦值,static構(gòu)造函數(shù)或者變量初始化時(shí)刻除外.

 

參考原文: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)和繼承(抽象類)


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI