天天看點

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

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

通路修飾符(或者叫通路控制符)是面向對象語言的特性之一,用于對類、類成員函數、類成員變量進行通路控制。同時,通路控制符也是文法保留關鍵字,用于封裝元件。

在建立類時,我們需要考慮類的作用域範圍,如誰可通路該類,誰可通路該類成員變量,誰可通路該類成員函數。 換而言之,我們需要限制類成員的通路範圍。一個簡單的規則,類成員函數、類成員變量之間可以自由

通路不受限制,這裡主要說的是外部的通路限制。在建立class的時候,預設的通路控制符為private。

下面做個小實驗,打開Visual Studio,建立一個C#的Console應用,命名為<code>AccessModifiers。 添加一個類,命名為<code>Modifiers ,拷貝如下代碼:</code></code>

上面的代碼建立了一個類Modifiers,它有2個static函數:AAA、BBB。其中BBB是public通路修飾符,在Main中調用BBB結果如下:

Modifiers BBB Modifiers AAA

BBB被标記為public,既任何函數皆可通路和運作。AAA被标記為private,既AAA僅能被其類内函數通路,外包是無法通路的。

修改代碼如下:

則運作報錯:

'AccessModifiers.Modifiers.AAA()' is inaccessible due to its protection level

下面我們對AAA進行重構,修改如下:

運作結果:

既,protected修飾符的成員變量,僅能被其同類、子類通路,外部無法通路。

我們接着添加子類,來擴充這個執行個體:

'AccessModifiers.ModifiersBase.AAA()' is inaccessible due to its protection level

原因是AAA預設為Private通路控制符,僅可在基類中通路,子類無法通路。

換另外一個場景,用Visual Studio建立一個dll類庫<code>AccessModifiersLibrary,添加一個ClassA類,标記為iternal修飾符,代碼如下:</code>

編譯後,會在~\AccessModifiersLibrary\bin\Debug下找到這個dll。 在<code>Program.cs使用這個dll, 添加dll引用,添加命名空間:</code>

編譯代碼,運作結果如下:

Compile time error: 'AccessModifiersLibrary.ClassA' is inaccessible due to its protection level

之是以報錯,是因為<code>internal 修飾符的作用域。<code>internal 修飾符僅對目前程式集(dll 或 exe)内有效,是以,當class添加internal修飾符則意味着程式集外無法通路。</code></code>

我們嘗試給命名空間添加修飾符,代碼如下:

運作報錯。

Compile time error: A namespace declaration cannot have modifiers or attributes

結論,我們無法對命名空間添加修飾符,命名空間預設是public的作用域。

修改如下代碼:

編譯報錯:

Compile time error: Elements defined in a namespace cannot be explicitly declared as private, protected, or protected internal

類可被修飾為public、internal,它無法被标記為protected或者private。類預設的修飾符為internal。

重構代碼如下:

編譯運作:

Compile time error: More than one protection modifier

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

重構代碼:

'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中添加如下代碼:

運作結果無錯誤。

<code>結論:Protected internal 修飾符做了2件事情,protected約定類類和繼承類通路控制,internal約定了隻能在目前程式集中。</code>

編譯結果:

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權限。

看代碼:

Compile time error: Inconsistent accessibility: base class 'AccessModifiers.AAA' is less accessible than class 'AccessModifiers.BBB'

子類不能比其基類的通路控制符作用域範圍大,如上面的例子中,基類為internal,而子類為public則報錯了。

去掉繼承,代碼重構為如下結果:

Inconsistent accessibility: return type 'AccessModifiers.AAA' is less accessible than method 'AccessModifiers.BBB.MethodB()'

這樣也編譯不通過,因為AAA為internal的通路類型,在public BBB中傳回了public的AAA,則意味着在其他程式集中也可能通路AAA,這樣是違法了internal修飾符原則,故編譯報錯。

同理,如下的代碼也是一樣的問題導緻編譯報錯:

如對代碼做重構,去掉BBB中AAA變量的修飾,既預設為private通路修飾符,則編譯沒有錯誤了。

參考MSDN中修飾符說明:

<a href="https://msdn.microsoft.com/zh-cn/library/yzh058ae.aspx">public</a>

同一程式集中的任何其他代碼或引用該程式集的其他程式集都可以通路該類型或成員。

<a href="https://msdn.microsoft.com/zh-cn/library/st6sy9xe.aspx">private</a>

隻有同一類或結構中的代碼可以通路該類型或成員。

<a href="https://msdn.microsoft.com/zh-cn/library/bcd5672a.aspx">protected</a>

隻有同一類或結構或者此類的派生類中的代碼才可以通路的類型或成員。

<a href="https://msdn.microsoft.com/zh-cn/library/7c5ka91b.aspx">internal</a>

同一程式集中的任何代碼都可以通路該類型或成員,但其他程式集中的代碼不可以。

protected internal

由其聲明的程式集或另一個程式集派生的類中任何代碼都可通路的類型或成員。 從另一個程式集進行通路必須在類聲明中發生,該類聲明派生自其中聲明受保護的内部元素的類,并且必須通過派生的類類型的執行個體發生。

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

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

Sealed修飾符的類,不可被其他類繼承。

運作報錯:

'AccessModifiers.BBB': cannot derive from sealed type 'AccessModifiers.AAA'
深入淺出OOP(五): C#通路修飾符(Public/Private/Protected/Internal/Sealed/Constants)

Sealed類使用如下:

運作正常。

100

結論,Const變量在初始化的時候設定了初始值,可被使用,但不可修改值。同時const變量支援互相引用運算。

但是請不要循環依賴,否則編譯器會檢測報錯:

檢測報錯:

The evaluation of the constant value for 'AccessModifiers.Program.x' involves a circular definition

<code>Class成員的預設修飾符為private</code>

class 被标記為<code>internal僅能被目前程式集通路</code>.

Namespace預設為public修飾符,且不能添加修飾符。

class可以使用<code>public 或</code> <code>internal修飾符</code>.不能使用修飾符 <code>protected</code>、 <code>private</code>. class預設的修飾符為<code>internal</code>.

類成員可使用所有修飾符,預設為 <code>private</code>.

<code>Protected internal修飾符約定了僅在繼承類内有效</code>.

<code>在public 與</code><code>internal修飾符之間,</code><code>public通常有更大的通路權限</code>.

基類必須必子類有更大的修飾符通路權限,才可被子類繼承.

函數傳回值的修飾符要有能通路傳回值的權限.

<code>sealed Class無法被子類繼承</code>.

<code>const變量,需要在聲明時完成初始化,在編碼階段不能初始化</code>.

類的const變量,可以彼此引用,但是不能形成循環引用.

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

<code>const變量不能被标記為</code><code>static</code>.

<code>Static 變量在類首次被加載時候初始化</code>. <code>int類型預設初始化為0,bool被初始化為False</code>.

<code>static readonly 字段無法被指派,</code><code>static構造函數或者變量初始化時刻除外</code>.

文章目錄:

<a href="http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Day-Polymorphism-and-Inheritance-Ear.html">深入淺出OOP(一): 多态和繼承(早期綁定/編譯時多态)</a>

<a href="http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Polymorphism-and-Inheritance-Part.html">深入淺出OOP(二): 多态和繼承(繼承)</a>

<a href="http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Day-Polymorphism-and-Inheritance-Dyn.html">深入淺出OOP(三): 多态和繼承(動态綁定/運作時多态)</a>

<a href="http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Day-Polymorphism-and-Inheritance-All.html">深入淺出OOP(四): 多态和繼承(抽象類)</a>

繼續閱讀