深刻淺出OOP(五): C#訪問修飾符(Public/Private/Protected/Inter

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

image

訪問修飾符(或者叫訪問控制符)是面嚮對象語言的特性之一,用於對類、類成員函數、類成員變量進行訪問控制。同時,訪問控制符也是語法保留關鍵字,用於封裝組件。less

Public, Private, Protected at Class Level

在建立類時,咱們須要考慮類的做用域範圍,如誰可訪問該類,誰可訪問該類成員變量,誰可訪問該類成員函數。 換而言之,咱們須要約束類成員的訪問範圍。一個簡單的規則,類成員函數、類成員變量之間能夠自由函數

訪問不受約束,這裏主要說的是外部的訪問約束。在建立class的時候,默認的訪問控制符爲private。編碼

下面作個小實驗,打開Visual Studio,建立一個C#的Console應用,命名爲AccessModifiers。 添加一個類,命名爲Modifiers ,拷貝以下代碼:lua

  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

 

Modifiers

下面咱們對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訪問控制符,僅可在基類中訪問,子類沒法訪問。

 

類級別的Internal 修飾符

換另一個場景,用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

結論,修飾符不支持嵌套。既每次僅能用一個修飾符。

 

Internal 類和Public成員函數

重構代碼:

  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修飾符,則該類僅能在程序集內可被訪問。

 

Protected 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約定了只能在當前程序集中。

 

Protected 類成員變量

  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中修飾符說明:

public

同一程序集中的任何其餘代碼或引用該程序集的其餘程序集均可以訪問該類型或成員。

private

只有同一類或結構中的代碼能夠訪問該類型或成員。

protected

只有同一類或結構或者此類的派生類中的代碼才能夠訪問的類型或成員。

internal

同一程序集中的任何代碼均可以訪問該類型或成員,但其餘程序集中的代碼不能夠。

protected internal

由其聲明的程序集或另外一個程序集派生的類中任何代碼均可訪問的類型或成員。 從另外一個程序集進行訪問必須在類聲明中發生,該類聲明派生自其中聲明受保護的內部元素的類,而且必須經過派生的類類型的實例發生。

 

同時,C#中類、枚舉、結構體等修飾符規則表以下:

image

 

 

Sealed Classes

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'

 

image

 

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: }

 

運行正常。

 

Constants

  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

 

本篇小結

  1. Class成員的默認修飾符爲private

  2. class 被標記爲internal僅能被當前程序集訪問.

  3. Namespace默認爲public修飾符,且不能添加修飾符。

  4. class能夠使用public 或 internal修飾符.不能使用修飾符 protected private. class默認的修飾符爲internal.

  5. 類成員可以使用全部修飾符,默認爲 private.

  6. Protected internal修飾符約定了僅在繼承類內有效.

  7. 在public 與 internal修飾符之間,public一般有更大的訪問權限.

  8. 基類必須必子類有更大的修飾符訪問權限,纔可被子類繼承.

  9. 函數返回值的修飾符要有能訪問返回值的權限.

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

  11. const變量,須要在聲明時完成初始化,在編碼階段不能初始化.

  12. 類的const變量,能夠彼此引用,可是不能造成循環引用.

  13. const變量在編譯器進行初始化,故const的運算可被執行.

  14. const變量不能被標記爲static.

  15. Static 變量在類首次被加載時候初始化. int類型默認初始化爲0,bool被初始化爲False.

  16. static readonly 字段沒法被賦值,static構造函數或者變量初始化時刻除外.

 

參考原文:Diving into OOP (Day 5): All About C# Access Modifiers (Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields)

 

文章目錄:

相關文章
相關標籤/搜索