アクセシビリティとはメソッド、プロパティ、クラスや構造体などへのアクセス許可の範囲のことを指します。 アクセシビリティの他にも、可視性スコープと呼ばれることもあります。

クラスのメソッドの呼び出しをクラス内からのみに限定するか、もしくはクラス外からも呼び出せるように公開するか、といったようにアクセス許可の範囲には様々な程度があります。 アクセス修飾子を指定することにより、メンバのアクセシビリティ、すなわちメンバに対するアクセス許可の範囲をどの程度に限定するか・どの範囲まで公開するかを指定することができます。

§1 アクセス修飾子とアクセシビリティ

アクセシビリティを指定するためのものがアクセス修飾子で、PublicやPrivateなどのキーワードがアクセス修飾子にあたります。 例えば次のようなクラスにおいて、Method1はアクセス修飾子Publicが指定されているためクラス外からも呼び出すことができますが、Method2はPrivateであるためクラス外からは呼び出せず、同一クラス内からのみ呼び出せます。

Class Sample
  ' アクセス修飾子Publicを指定したメソッド
  ' (このメソッドはSampleクラス外からのアクセスも可能)
  Public Sub Method1()
  End Sub

  ' アクセス修飾子Privateを指定したメソッド
  ' (このメソッドはSampleクラス内からのアクセスのみ可能)
  Private Sub Method2()
  End Sub
End Class

PublicやPrivate以外にも、アクセス範囲を限定するための様々なアクセス修飾子があります。 アクセス修飾子の種類とその概要は次のとおりです。

アクセス修飾子のアクセシビリティ
アクセス修飾子 適用されるアクセシビリティ 詳細
Public すべての箇所からのアクセスを許可 同じプロジェクト内・他のプロジェクトのすべての箇所からのアクセスが可能とするように公開する
Friend プロジェクト内からのアクセスのみ許可 同じプロジェクト内からのアクセスは可能とするが、他のプロジェクトからのアクセスは不可能とするように公開する
(同じプロジェクト内からのアクセスに対してはPublic、他のプロジェクトからのアクセスに対してはPrivateとなる)
Protected クラス内、または派生クラスからのアクセスのみ許可 同じクラス内および派生クラスからのアクセスは可能とするが、クラス外および継承関係にないクラスからのアクセスは不可能とするように公開する
Protected Friend プロジェクト内、クラス内、または派生クラスからのアクセスのみ許可 同じクラス内および派生クラス、同じプロジェクト内からのアクセスは可能とするが、他のプロジェクトおよび他のプロジェクトで宣言される派生クラスからのアクセスは不可能とするように公開する
(同じプロジェクト内からのアクセスに対してはPublic、他のプロジェクトからのアクセスに対してはProtectedとなる)
Private クラス内からのアクセスのみ許可 同じクラス内からのアクセスは可能とするが、派生クラスやクラス外からのアクセスは不可能とする
(クラス外には一切公開しない)

アクセス修飾子にFriendが設定されているメンバは、同じプロジェクト内(厳密には同じアセンブリ)からのアクセスに対してはPublicと同様にすべての箇所からアクセスすることができますが、他のプロジェクトからはPrivateと同様に一切アクセスすることはできません。 クラスライブラリを作成する際、クラスライブラリ内からのアクセスは許可したいが、クラスライブラリの利用者にはアクセスを許可しないメソッドを作りたい、といった場面でアクセス修飾子Friend(およびProtected Friend)を使うことができます。

具体例については後述するFriendとProtected Friendの例型をPrivate・Protectedにする例もあわせてご覧ください。



§2 アクセス修飾子を適用できる対象

アクセス修飾子は、クラスやメソッドだけでなくメンバ変数やプロパティ、構造体などにも指定することができます。 ただし、すべてのアクセス修飾子をすべての要素に指定できるわけではなく、対象によっては指定できないアクセス修飾子もあります。

次の表は、各アクセス修飾子とそのアクセス範囲、アクセス修飾子を適用できる要素をまとめたものです。

アクセス修飾子を適用できる対象
アクセス修飾子 適用できる対象
クラス 構造体 モジュール クラスメンバ 構造体メンバ モジュールメンバ ローカル変数
Public
Friend
Protected
Protected Friend
Private
Dim

表中の◎はアクセス修飾子を指定しなかった場合のデフォルトのアクセシビリティです。 例えば構造体ではメソッドにアクセス修飾子を指定しなかった場合はPublicとして扱われますが、クラスではメソッドにアクセス修飾子を指定しなかった場合はPrivateとして扱われます。

Dimはローカル変数の宣言だけでなくクラス・構造体のメンバ変数を宣言する際にも指定することができます。 Dim自体はアクセス修飾子ではありませんが、Dimを使って宣言されたメンバ変数のアクセシビリティはデフォルトと同じ、つまり構造体ではPublic、クラス・モジュールではPrivateで宣言されているのと同じものとして扱われます。

ローカル変数はメソッド内でのみ有効である(ローカル変数はメソッド外に公開できない)ため、アクセス修飾子を指定することはできません。 (ブロックと変数のスコープ)

§3 アクセス修飾子の適用例

次のサンプルはアクセス修飾子の適用とメンバの公開範囲を例示したものです。 詳細はコメントにあるとおりです。

アクセス修飾子の適用例
' このクラスはプロジェクト外にも公開される
Public Class C
  ' このメソッドはクラス外にも公開される
  Public Sub Method1()
  End Sub

  ' このメソッドはクラス内のみに公開される
  Private Sub Method2()
  End Sub

  ' このメソッドはクラス内のみに公開される (=Private)
  Sub Method3()
  End Sub

  ' このフィールドはクラス外にも公開される
  Public Field1 As Integer

  ' このフィールドはクラス内および派生クラスにのみ公開される
  Protected Field2 As Integer

  ' このフィールドはクラス内にのみ公開される
  Private Field3 As Integer

  ' このフィールドはクラス内にのみ公開される (=Private)
  Dim Field4 As Integer
End Class

' この構造体はプロジェクト外には公開されない (=Friend)
Structure S
  ' このメソッドは構造体外にも公開される
  Public Sub Method1()
  End Sub

  ' このメソッドは構造体内にのみ公開される
  Private Sub Method2()
  End Sub

  ' このメソッドは構造体外にも公開される (=Public)
  Sub Method3()
  End Sub

  ' このフィールドは構造体外にも公開される
  Public Field1 As Integer

  ' このフィールドは構造体内にのみ公開される
  Private Field2 As Integer

  ' このフィールドは構造体外にも公開される (=Public)
  Dim Field3 As Integer
End Structure

Class Sample
  Shared Sub Main()
    Dim c As New C

    ' クラスCのこれらのメンバにはアクセス可能
    c.Method1()
    c.Field1 = 16

    Dim s As S

    ' 構造体Sのこれらのメンバにはアクセス可能
    s.Method1()
    s.Method3()
    s.Field1 = 42
    s.Field3 = 3
  End Sub
End Class

§3.1 型のアクセシビリティとメンバの公開範囲

メンバの公開範囲は型の公開範囲より広くすることはできません。 例えば、Friendアクセス修飾子が指定されているモジュールの場合、このモジュールはプロジェクト内からしかアクセスできません。 このモジュール内でPublic修飾子を指定したメソッドを宣言したとしても、そのメソッドはモジュール自体と同じくプロジェクト内からしかアクセスできません。

' このモジュールはプロジェクト外にも公開される
Public Module M1
  ' このメソッドはプロジェクト外からも呼び出すことができる
  Public Sub Method1()
  End Sub
End Module

' このモジュールはプロジェクト外には公開されない
Friend Module M2
  ' このメソッドはプロジェクト外から呼び出すことはできない
  Public Sub Method1()
  End Sub

  ' Method1と以下のMethod2は同じアクセシビリティとなる
  Friend Sub Method2()
  End Sub
End Module

公開範囲についてはネストされた型の場合もあわせてご覧ください。

§4 FriendとProtedted Friend

アクセス修飾子FriendとProtected Friendが指定されたメンバは、同じプロジェクト(アセンブリ)内ではどちらもPublicと同様のアクセシビリティを持ちます。

Project1
Public Class C
  ' このメソッドはプロジェクト内にのみ公開される
  Friend Sub M1()
  End Sub

  ' このメソッドはプロジェクト内、および派生クラスにのみ公開される
  Protected Friend Sub M2()
  End Sub

  ' このメソッドはプロジェクト外にも公開される
  Public Sub M3()
  End Sub
End Class

Class X
  Sub M()
    Dim c As New C

    ' クラスCのメソッドM1およびM2は、同じプロジェクト内から見れば
    ' Publicと同様なので呼び出すことができる
    c.M1()
    c.M2()

    ' 当然、クラスCのメソッドM3も呼び出すことができる
    c.M3()
  End Sub
End Class

一方で、別のプロジェクト(アセンブリ)からはアクセス修飾子Friendが指定されたメンバはPrivate、Protected Friendが指定されたメンバはProtectedと同様のアクセシビリティとなります。 上記のプロジェクトProject1で定義されているクラスCを使用する別のプロジェクトProject2では、各メソッドのアクセシビリティは次のようになります。

Project2
Class C1
  Inherits C ' Project1のクラスCを継承

  Sub M()
    ' Project1で定義されているクラスCのメソッドM1はFriendであり、
    ' Project2から見るとPrivateなメソッドと同様なので呼び出すことはできない
    'M1()

    ' 一方クラスCのメソッドM2はFriend Protectedで、
    ' Project2から見るとProtectedなメソッドと同様なので呼び出すことができる
    M2()

    ' 当然、クラスCのメソッドM3はPublicであるため呼び出すことができる
    M3()
  End Sub
End Class

Class Y
  Sub M()
    ' Project1で定義されているクラスCはPublicなのでインスタンスを
    ' 作成することができる
    Dim c As New C

    ' クラスCのメソッドM1、M2はPublicではないので別のプロジェクトから
    ' 呼び出すことはできない
    'c.M1()
    'c.M2()

    ' 一方クラスCのメソッドM3はPublicであるため呼び出すことができる
    c.M3()
  End Sub
End Class

§5 プロパティとアクセシビリティ

プロパティでは、SetプロシージャとGetプロシージャで異なるアクセシビリティを設定することができます。 これにより、クラス外からの値の取得は許可するが、値の設定はクラス内のみに限定する、といったプロパティを用意することができます。

Class C
  Dim _p as Integer

  Property P As Integer
    ' プロパティPへの値の設定はクラス内および派生クラスからのみに限定する
    Protected Set (ByVal val As Integer)
      _p = val
    End Set
    ' プロパティPの値の取得はクラス内外両方に許可する
    Public Get
      Return _p
    End Get
  End Property
End Class

プロパティ宣言自体にアクセス修飾子を指定した場合は、SetプロシージャとGetプロシージャにそのアクセシビリティが適用されます。 プロパティ宣言自体にアクセス修飾子が指定されていても、SetプロシージャまたはGetプロシージャにアクセス修飾子を指定すれば、そのアクセシビリティが適用されます。

Class C
  Dim _p as Integer

  ' PublicなプロパティPを宣言
  Public Property P As Integer
    ' Privateが指定されているため、プロパティPへの値の設定はクラス内のみで可能となる
    Private Set (ByVal val As Integer)
      _p = val
    End Set
    ' アクセス修飾子が指定されていないため、プロパティPの値の取得はPublicとなる
    Get
      Return _p
    End Get
  End Property
End Class

プロパティ宣言の構文についてはプロパティを参照してください。

§6 ネストされた型とPrivate・Protected

クラス・構造体・モジュール自体にもPrivateアクセス修飾子を指定することはできますが、名前空間直下に属するものにはPrivateを指定することはできません。 Privateが指定できるのはいずれかの型の中で宣言された型、つまりネストされたクラス・構造体・モジュールのみです。 クラスであれば、これらは入れ子クラス・内部クラス・インナークラスなどと呼ばれます。

ネストされた型のメンバを参照できるようにするには、そのメンバにアクセス修飾子PublicもしくはFriendを指定する必要があります。 アクセス修飾子Privateを指定した場合は、ネストされた型の内部のみでしか参照できなくなります。

ネストされた型とアクセシビリティの例
Class C
  ' Publicなインナークラス
  Public Class CI1
    ' このメソッドはクラス外に公開される
    Public Sub M1()
    End Sub
  End Class

  ' Privateなインナークラス
  Private Class CI2
    ' このメソッドはクラスCI2外に公開される
    Public Sub M1()
    End Sub

    ' このメソッドはクラスCI2外には公開されない
    Private Sub M2()
    End Sub
  End Class

  Sub M()
    ' インナークラスCI1は同一クラス内で宣言されているのでインスタンスを作成できる
    Dim ci1 As New CI1

    ' インナークラスCI1のメソッドM1はPublicなので呼び出すことができる
    ci1.M1()

    ' インナークラスCI2も同様に同一クラス内で宣言されているのでインスタンスを作成できる
    Dim ci2 As New CI2

    ' インナークラスCI2のメソッドM1はPublicなので呼び出すことができる
    ci2.M1()

    ' 一方メソッドM2はPrivateなので呼び出すことはできない
    'ci2.M2()
  End Sub
End Class

Class X
  Sub M()
    ' クラスCのインナークラスCI1はPublicなのでインスタンスを
    ' 作成することができる
    Dim ci1 As New C.CI1

    ' 一方インナークラスCI2はPrivateなのでインスタンスを
    ' 作成することができる
    'Dim ci2 As New C.CI2
  End Sub
End Class

クラスの場合、ネストされた型にアクセス修飾子Protectedを指定することができます。 Protectedが指定された型は、型が宣言されているクラスとその派生クラスにのみ公開されます。

Protectedなインナークラスの例
Class C
  ' Protectedなインナークラス
  Protected Class CI
  End Class
End Class

Class C1
  ' クラスCを継承
  Inherits C

  Sub M()
    ' インナークラスCIは基底クラスCで宣言されたProtectedなクラスなので
    ' インスタンスを作成できる
    Dim ci As New CI
  End Sub
End Class

Class X
  Sub M()
    ' クラスXはクラスCとは継承関係にないため、インナークラスCIの
    ' インスタンスを作成することはできない
    Dim ci As New C.CI
  End Sub
End Class

§6.1 ネストされた型と親クラスのメンバのアクセシビリティ

ネストされた型からは親クラスのすべてのメンバを参照することができます。 例えば、次のようにインナークラスから親クラスのPrivateなメソッドを呼び出すこともできます。

インナークラスから親クラスのメンバを参照する例
Class C
  ' Privateなメソッド
  Private Sub M()
  End Sub

  ' インナークラス
  Private Class CI
    Private c As C

    ' コンストラクタで親クラスのインスタンスを受け取る
    Public Sub New(ByVal c As C)
      MyClass.c = c
    End Sub

    Sub M()
      ' 親クラスCのPrivateなメソッドMを呼び出す
      c.M()
    End Sub
  End Class
End Class

§7 インターフェイスの実装とアクセシビリティ

インターフェイスの実装となるメンバは、そのアクセシビリティと無関係に参照可能となる点に注意が必要です。 次の例のように、インターフェイスのメソッドをPrivateなメソッドとして実装していたとしても、インターフェイス型にキャストすればそのメソッドを呼び出すことが可能となります。

インターフェイスを介してPrivateなメンバを参照する例
Class C
  ' IDisposableインターフェイスを実装する
  Implements IDisposable

  ' IDisposable.Disposeの実装となるメソッド
  Private Sub Dispose() Implements IDisposable.Dispose
    Console.WriteLine("disposed")
  End Sub
End Class

Class Sample
  Shared Sub Main()
    Dim c As New C

    ' C.DisposeメソッドはPrivateなので直接呼び出すことはできない
    'c.Dispose()

    ' CをIDisposableにキャスト
    Dim d As IDisposable = DirectCast(c, IDisposable)

    ' C.DisposeメソッドがPrivateでも、IDisposableインターフェイスを介して
    ' Disposeメソッドを呼び出すことができる
    d.Dispose()
  End Sub
End Class