ここでは、public、protected、internal、private、protected internal(VB.NETではそれぞれ、Public、Protected、Friend、Private、Protected Friend)をクラスのメンバに使用した時どのような違いがあるのかについて説明します。
このことについて、MSDN(「アクセシビリティ レベル」、VB.NETでは「アクセシビリティ」)では次のように説明されています。
宣言されたアクセシビリティ | 説明 |
---|---|
public (Public) | アクセスの制限はありません。 |
protected (Protected) | アクセスは、コンテナ クラス、またはコンテナ クラスから派生した型に制限されます。 |
internal (Friend) | アクセスは現在のアセンブリに制限されます。 |
protected internal (Protected Friend) | アクセスは、現在のアセンブリ、またはコンテナ クラスから派生した型に制限されます。 |
private (Private) | アクセスはコンテナ型に制限されます。 |
これだけでは何のことだか、さっぱり分かりません(分かる方はこれ以上お読みいただく必要はありません)。そこでここでは具体例を挙げてそれぞれの違いを説明します。
まずは、publicとprivateの違いを知っておきましょう。初心者の方はとりあえずこれだけ覚えておいてください。
Class Class1 'Publicフィールド Public PublicValue As Integer 'Privateフィールド Private PrivateValue As Integer 'Publicメソッド Public Sub SetValue(ByVal val As Integer) 'パブリックメンバにはもちろんアクセスできる PublicValue = val 'プライベートメンバにも同じクラス内ではアクセスできる PrivateValue = val End Sub End Class Class MainClass Public Shared Sub Main() Dim c As New Class1 '「...: 'Class1.PrivateValue' は ' アクセスできない保護レベルになっています。」 'というエラーが出る c.PrivateValue = 0 'Publicであれば問題なし c.PublicValue = 1 c.SetValue(0) End Sub End Class
class Class1 { //publicフィールド public int PublicValue; //privateフィールド private int PrivateValue; //publicメソッド public void SetValue(int val) { //パブリックメンバにはもちろんアクセスできる PublicValue = val; //プライベートメンバにも同じクラス内ではアクセスできる PrivateValue = val; } } class MainClass { public static void Main() { Class1 c = new Class1(); //「...: 'Class1.PrivateValue' は // アクセスできない保護レベルになっています。」 //というエラーが出る c.PrivateValue = 0; //publicであれば問題なし c.PublicValue = 1; c.SetValue(0); } }
上記のコードでは、MainClassクラスから、外部のクラスClass1のフィールド(メンバ変数)に新しい値を代入しようとしています。この時、publicが指定されたフィールドPublicValue(パブリックメンバ、公開メンバなどと呼ぶ)への代入は問題なく行えますが、これに対してprivateが指定されたフィールドPrivateValue(プライベートメンバ、私的メンバなどと呼ぶ)への代入では、エラーが発生して失敗します(コンパイルで失敗します)。しかしこのPrivateValueへの代入も、宣言されているクラス内(Class1内)では問題なく行えます。
上記のMSDNでの説明をこのケースに当てはめると、
public (Public) : どのクラスからもアクセスできる。
private (Private) : そのメンバが宣言されているクラス内でアクセスできる。
となるでしょう。
結局その使い分けは、
どこからでも使いたいフィールド(メンバ変数)、メソッド、プロパティ、クラス、構造体などにはpublicを指定し、そのクラス内でしか使用しないものにはprivateを指定する
と覚えておけば、初心者の方はとりあえずOKでしょう。
ここからは、残りの説明です。まず、protectedが指定されたメンバには、そのメンバが宣言されているクラス内と、そのクラスから派生したクラス内からのみアクセスできます。つまりprotectedメンバのアクセス範囲は、
「private + 派生したクラス内」
となります。
internalが指定されたメンバには、そのメンバと同じアセンブリファイル(EXEファイルやDLLファイル)内からのみアクセスできます。
最後に、protected internalが指定されたメンバは、
「protected + internal」
のアクセス範囲を持ちます。
さてここでクラスライブラリ(DLL)とそれを使う実行ファイル(EXE)からなる簡単なプログラムを作成し、以上のアクセス修飾子のアクセス範囲を確認しましょう。まずは次のようなクラスライブラリを作成します。
Namespace ClassLibrary Public Class Class1 'Publicフィールド Public PublicValue As Integer = 0 'Privateフィールド Private PrivateValue As Integer = 0 'Protectedフィールド Protected ProtectedValue As Integer = 0 'Friendフィールド Friend FriendValue As Integer = 0 'Protected Friendフィールド Protected Friend ProtectedFriendValue As Integer = 0 '入れ子になったクラス Public Class Class11 Public Sub Method1() Dim c As New Class1 Dim i As Integer 'OK i = c.PrivateValue End Sub End Class End Class Public Class Class2 Public Sub Method1() Dim c As New Class1 Dim i As Integer 'OK i = c.PublicValue 'エラー:アクセスできない保護レベル 'i = c.PrivateValue 'エラー:アクセスできない保護レベル 'i = c.ProtectedValue 'OK i = c.FriendValue 'OK i = c.ProtectedFriendValue End Sub End Class 'Class1からの派生クラス Public Class Class3 Inherits Class1 Public Sub Method1() Dim i As Integer 'OK i = PublicValue 'エラー:アクセスできない保護レベル 'i = PrivateValue 'OK i = ProtectedValue 'OK i = FriendValue 'OK i = ProtectedFriendValue End Sub End Class End Namespace
namespace ClassLibrary { public class Class1 { //publicフィールド public int PublicValue = 0; //privateフィールド private int PrivateValue = 0; //protectedフィールド protected int ProtectedValue = 0; //internalフィールド internal int InternalValue = 0; //protected internalフィールド protected internal int ProtectedInternalValue = 0; //入れ子になったクラス public class Class11 { public void Method1() { Class1 c = new Class1(); int i; //OK i = c.PrivateValue; } } } public class Class2 { public void Method1() { Class1 c = new Class1(); int i; //OK i = c.PublicValue; //エラー:アクセスできない保護レベル //i = c.PrivateValue; //エラー:アクセスできない保護レベル //i = c.ProtectedValue; //OK i = c.InternalValue; //OK i = c.ProtectedInternalValue; } } //Class1からの派生クラス public class Class3 : Class1 { public void Method1() { int i; //OK i = PublicValue; //エラー:アクセスできない保護レベル //i = PrivateValue; //OK i = ProtectedValue; //OK i = InternalValue; //OK i = ProtectedInternalValue; } } }
次にこのライブラリを使用する実行ファイルを作成します。
Namespace Console1 Class MainClass Public Shared Sub Main() Dim c As New ClassLibrary.Class1 Dim i As Integer 'OK i = c.PublicValue 'エラー:アクセスできない保護レベル 'i = c.PrivateValue 'エラー:アクセスできない保護レベル 'i = c.ProtectedValue 'エラー:アクセスできない保護レベル 'i = c.FriendValue 'エラー:アクセスできない保護レベル 'i = c.ProtectedFriendValue End Sub End Class Class Class1 Inherits ClassLibrary.Class1 Public Sub Method1() Dim i As Integer 'OK i = PublicValue 'エラー:アクセスできない保護レベル 'i = PrivateValue 'OK i = ProtectedValue 'エラー:アクセスできない保護レベル 'i = FriendValue 'OK i = ProtectedFriendValue End Sub End Class End Namespace
namespace Console1 { class MainClass { public static void Main() { ClassLibrary.Class1 c = new ClassLibrary.Class1(); int i; //OK i = c.PublicValue; //エラー:アクセスできない保護レベル //i = c.PrivateValue; //エラー:アクセスできない保護レベル //i = c.ProtectedValue; //エラー:アクセスできない保護レベル //i = c.InternalValue; //エラー:アクセスできない保護レベル //i = c.ProtectedInternalValue; } } class Class1 : ClassLibrary.Class1 { public void Method1() { int i; //OK i = PublicValue; //エラー:アクセスできない保護レベル //i = PrivateValue; //OK i = ProtectedValue; //エラー:アクセスできない保護レベル //i = InternalValue; //OK i = ProtectedInternalValue; } } }
上記のコードでは、アクセスできず、エラーの発生する行のコードはコメントアウトされています。このコードをご覧いただければ、それぞれのアクセス範囲は一目瞭然でしょう。
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。