Meはクラスや構造体のインスタンス自身を参照するためのキーワードです。 MyClassもインスタンス自身のメンバを参照する点はMeと同じですが、呼び出そうとするメソッドがオーバーライドされていてもMyClassが使われたクラスの実装が呼び出されるという点がMeとは異なります。 MyClassは自クラスのメンバを参照する場合に使用するのに対して、MyBaseは基底クラスのメンバを参照する際に使用します。
この他にもMe・MyClass・MyBaseとは役割は異なるものの似た名前を持つものとしてMy名前空間というものも存在します。
MeとMyClass
MeとMyClassはよく似た機能を持つキーワードです。 ともにクラスまたは構造体のインスタンス自身のメンバを参照するキーワードで、クラス・構造体の内部でのみ使用することができます。 MeとMyClassが使われる場面と相違点をまとめると次のようになります。
機能 | 相違点 | |
---|---|---|
Me | MyClass | |
インスタンス自身のメンバの参照 | できる | できる |
隠蔽されたメンバの参照 | できる | できる |
コンストラクタの呼び出し | できる | できる |
オーバーライドを無視したメソッドの呼び出し | できない | できる |
インスタンス自身の引渡し | できる | できない |
以下でMeとMyClassが使われる個々の場面と、そこでのMe・MyClassの違いについて見ていきます。
インスタンス自身のメンバの参照
クラスの外部からメンバ(フィールドやメソッドなど)にアクセスする場合、変数.メンバ名
とします。 これと同様に、クラス内部からメンバにアクセスする場合、Me.メンバ名
とします。 このMeはインスタンス自身を表します。 ただ、通常はMeを省略して単にメンバ名
とします。
Class C
Public Field As Integer = 42
Public Sub Method1()
' 現在のインスタンス自身のフィールドFieldを参照する
Console.WriteLine(Field)
' Meを付けて参照することもできる
Console.WriteLine(Me.Field)
End Sub
Public Sub Method2()
' 現在のインスタンス自身のメソッドMethod1を呼び出す
Method1()
' Meを付けて参照することもできる
Me.Method1()
End Sub
End Class
Module Sample
Public Sub Main()
Dim c As New C()
' 変数cに代入されているインスタンスのフィールドFieldを参照する
c.Field = 16
' 変数cに代入されているインスタンスのメソッドMethod1を呼び出す
c.Method1()
End Sub
End Module
構造体の場合も同様にMeでインスタンス自身のメンバを参照できます。
Structure S
Public Field As Integer = 42
Public Sub Method1()
' 現在のインスタンス自身のフィールドFieldを参照する
Console.WriteLine(Field)
' Meを付けて参照することもできる
Console.WriteLine(Me.Field)
End Sub
End Structure
MeではなくMyClassでインスタンス自身のメンバを参照することもできます。
Class C
Public Field As Integer = 42
Public Sub Method1()
' MyClassでインスタンス自身のメンバを参照する
Console.WriteLine(MyClass.Field)
' Meでインスタンス自身のメンバを参照する
Console.WriteLine(Me.Field)
End Sub
End Class
このようにMe・MyClassでインスタンス自身のメンバを参照することを明示できます。 ここまでで紹介した例ではMe・MyClassを省略することもできますが、隠蔽されたメンバを参照する場合はMe・MyClassを明記する必要があります。
隠蔽されたメンバの参照
メソッドがクラスや構造体のフィールド(メンバ変数)と同名の引数をとる場合、そのメソッド内では同名のメンバは隠蔽されます。 次の例では、コンストラクタの引数にx
とy
があり、この引数が同名のフィールドx
とy
を隠蔽します。 そのため、x
とy
はインスタンスのフィールドではなくコンストラクタの引数x
とy
を表すことになります。 この例において、引数x
とy
の値はフィールドには代入されず、意図したとおりには初期化されません。
Structure Point
Private x As Integer
Private y As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
' 引数xの値をインスタンスのフィールドxに代入したい
x = x
' 同様に引数yの値をフィールドyに代入したい
y = y
End Sub
Public Sub Print()
Console.WriteLine("({0}, {1})", x, y)
End Sub
End Structure
Module Sample
Public Sub Main()
Dim p As New Point(640, 480)
p.Print()
End Sub
End Module
(0, 0)
このように隠蔽されたメンバは存在しなくなるわけではなく、MeまたはMyClassを使うことで隠蔽されたメンバを参照することができます。
Structure Point
Private x As Integer
Private y As Integer
Public Sub New(ByVal x As Integer, ByVal y As Integer)
' 引数xの値をインスタンスのフィールドxに代入する
Me.x = x
' 引数yの値をインスタンスのフィールドyに代入する
Me.y = y
' MyClassでも隠蔽されたメンバを参照することができる
MyClass.x = x
MyClass.y = y
End Sub
Public Sub Print()
Console.WriteLine("({0}, {1})", x, y)
End Sub
End Structure
引数の場合のほかにも、ローカル変数の場合でも同名のメンバが隠蔽されます。 この場合でも、Me・MyClassを使うことでローカル変数に隠蔽されたメンバを参照することができます。
Structure Point
Private x As Integer
Private y As Integer
Public Sub Test()
' フィールドと同名のローカル変数を宣言する
Dim x As Integer = 16
Dim y As Integer = 42
' ローカル変数のx, yの値が表示される
Console.WriteLine(x)
Console.WriteLine(y)
' インスタンスのフィールドx, yの値が表示される
Console.WriteLine(Me.x)
Console.WriteLine(Me.y)
Console.WriteLine(MyClass.x)
Console.WriteLine(MyClass.y)
End Sub
End Structure
MeやMyClassを使って隠蔽されたメンバを参照するよりも、メンバ名と同名の引数名・変数名を付けることを避けたほうが分かりやすく、無難です。
コンストラクタの呼び出し
コンストラクタでは、引数の異なる別のコンストラクタを呼び出すことができます。 この場合、メソッド呼び出しのようにコンストラクタを直接New(...)
として呼び出すことはできません。 必ずMeもしくはMyClassを伴ってMe.New(...)
やMyClass.New(...)
のように呼び出す必要があります。
Class Account
' この二つのフィールドは必須としたい
Public Name As String
Public ID As Integer
' このフィールドは省略可能としたい
Public MailAddress As String
' 必須のパラメータのみを指定するコンストラクタ
Public Sub New(ByVal name As String, ByVal id As Integer)
' 省略されたパラメータのデフォルトとしてNothingを指定して別のコンストラクタを呼び出す
Me.New(name, id, Nothing)
' Meの代わりにMyClassを使ってコンストラクタを呼び出すこともできる
'MyClass.New(name, id, Nothing)
End Sub
' 省略可能なパラメータも指定可能なコンストラクタ
Public Sub New(ByVal name As String, ByVal id As Integer, ByVal mailAddress As String)
Me.Name = name
Me.ID = id
Me.MailAddress = mailAddress
End Sub
End Class
オーバーライドを無視したメソッドの呼び出し
クラスを継承してメソッドをオーバーライドすると、基底クラスのメソッドの動作を変更することができます。 基底クラス内からオーバーライド可能なメソッドを呼び出す場合、派生クラスでメソッドがオーバーライドされていれば、そのメソッドが呼び出されます。
' 基底クラス
Class BaseClass
Public Sub CallMethod()
' オーバーライドされている可能性のあるメソッドを呼び出す
Method()
End Sub
' 派生クラスでオーバーライド可能なメソッド
Protected Overridable Sub Method()
Console.WriteLine("BaseClass")
End Sub
End Class
' 派生クラス
Class DerivedClass
Inherits BaseClass
' 基底クラスのメソッドをオーバーライドして動作を変更したメソッド
Protected Overrides Sub Method()
Console.WriteLine("DerivedClass")
End Sub
End Class
Module Sample
Public Sub Main()
' 派生クラスのインスタンスを作成
Dim i As New DerivedClass()
' オーバーライドされているメソッドを呼び出す
i.CallMethod()
End Sub
End Module
DerivedClass
MeおよびMyClassを使ってオーバーライドされているメソッドを呼び出す場合、両者は同じ動作とはならない点に注意が必要です。 Meキーワードでオーバーライドされているメソッドを呼び出す場合は、Meを省略して呼び出した場合と同じく派生クラスでオーバーライドされた方のメソッドが呼び出されますが、MyClassキーワードではMyClassが使用されたクラスのメソッドが呼び出されます。
Imports System
Imports System.Collections.Generic
' 基底クラス
Class BaseClass
Public Sub CallMethodByMe()
' Meを使ってオーバーライドされている可能性のあるメソッドを呼び出す
Me.Method()
End Sub
Public Sub CallMethodByMyClass()
' MyClassを使ってオーバーライドされている可能性のあるメソッドを呼び出す
MyClass.Method()
End Sub
' 派生クラスでオーバーライド可能なメソッド
Protected Overridable Sub Method()
Console.WriteLine("BaseClass")
End Sub
End Class
' 派生クラス
Class DerivedClass
Inherits BaseClass
' 基底クラスのメソッドをオーバーライドして動作を変更したメソッド
Protected Overrides Sub Method()
Console.WriteLine("DerivedClass")
End Sub
End Class
Module Sample
Public Sub Main()
' 派生クラスのインスタンスを作成
Dim i As New DerivedClass()
' Meを使ってオーバーライドされているメソッドを呼び出す
i.CallMethodByMe()
' MyClassを使ってオーバーライドされているメソッドを呼び出す
i.CallMethodByMyClass()
End Sub
End Module
DerivedClass BaseClass
Meではメソッドのオーバーライドが有効になるのに対し、MyClassではオーバーライドが無視されると見ることができます。 言い換えると、Meではオーバーライドの影響を受けるのに対し、MyClassではオーバーライドの影響を受けない、となります。
もしくは、Meではインスタンス自身(=Me)が派生クラスかどうかを考慮してメソッド呼び出しを行うのに対し、MyClassでは常に自分のクラス(=MyClass)のメソッドを呼び出すと見ることもできます。
なお、コンストラクタ(Newメソッド)も一種のメソッドとみなされますが、コンストラクタはオーバーライドできないためMeとMyClassのどちらを使って呼び出しても動作が変わることはありません。
インスタンス自身の引渡し
RaiseEventによってイベントを発生させる場合や、メソッドの引数としてインスタンス自身を渡す場合にはMeを使います。 MyClassではインスタンス自身を引き渡すことはできません。
Class Control
Public Event Click As EventHandler
Private Sub OnClick(ByVal sender As Object, ByVal e As EventArgs)
' Clickイベントを発生させる
RaiseEvent Click(sender, e)
End Sub
Public Sub RaiseClick()
' イベント発生源として自分自身のインスタンスを渡してイベントを発生させる
OnClick(Me, EventArgs.Empty)
' 自分自身のインスタンスを渡す目的でMyClassを使用することはできない
OnClick(MyClass, EventArgs.Empty)
' error BC32028: 'MyClass' の後には '.' および識別子を指定しなければなりません。
End Sub
End Class
MeとMyClassの違いと使い分け
このようにMeとMyClassは機能や役割が似ていますが、全く同じではないため正しく使い分ける必要があります。 Meではクラス外部からメンバを参照する場合と同じように実際のインスタンスの型が考慮される動作となるのに対し、MyClassでは参照するメンバをインスタンスの型に関わらず現在のクラスに限定する動作となります。
MeとMyClassの使い分けを整理すると次のようになります。
- インスタンス自身を引数として渡す場合はMe
- オーバーライドを無視して自クラスのメソッドの呼び出しを行う場合はMyClass
- オーバーライドされないメンバや隠蔽されたメンバを参照する場合はMeでもMyClassでも可
VBのMeキーワードとMyClassキーワードはC#におけるthis
にほぼ相当するものですが、C#のthis
ではオーバーライドを無視して自クラスのメソッドを呼び出すことはできません。 このようなMyClassの動作はVB固有の動作です。
MyBase
MyBaseは基底クラスのメンバを参照する際に使用します。 派生クラスからはMyBase.メンバ
とすることで基底クラスのメンバを参照することができます。 ただ、MeやMyClassと同様にMyBaseを省略しても基底クラスから継承されたメンバを参照することはできます。
メソッドがオーバーライド(Overrides
)または隠蔽(Shadows
)されることにより基底クラスの実装が隠されている場合には、MyBaseを明記して呼び出す必要があります。
Class Control
Public Event Click As EventHandler
Protected Overridable Sub OnClick(ByVal e As EventArgs)
' Clickイベントを発生させる
RaiseEvent Click(Me, e)
End Sub
Public Sub RaiseClick()
OnClick(EventArgs.Empty)
End Sub
End Class
Class Button
Inherits Control
Public Enabled As Boolean
' メソッドをオーバーライドしてOnClickメソッドの動作を変える
Protected Overrides Sub OnClick(ByVal e As EventArgs)
' EnabledがTrueの場合のみ、基底クラスのOnClickメソッドを呼び出してClickイベントを発生させる
If Enabled Then MyBase.OnClick(e)
End Sub
End Class
コンストラクタから基底クラスのコンストラクタを呼び出す場合も、MyBaseを明記します。
Class Control
Public Parent As Control
Public Sub New(ByVal parent As Control)
Me.Parent = parent
End Sub
End Class
Class Button
Inherits Control
Public Sub New(ByVal parent As Control)
' 基底クラスのコンストラクタを呼び出して初期化する
MyBase.New(parent)
' 必要に応じて追加の初期化処理を記述する
End Sub
End Class
派生クラスで基底クラスと同名のフィールドを宣言した場合も、基底クラス側のフィールドが隠蔽されます。 隠蔽された基底クラスのフィールドを参照する場合にもMyBaseを明記します。
Class BaseClass
Public Field As Integer
End Class
Class DerivedClass
Inherits BaseClass
' 基底クラスで宣言されているものと同名のフィールド
Public Field As Integer
Public Sub Print()
' 基底クラスのFieldを参照する
MyBase.Field = 42
' このクラスのFieldを参照する
Field = 3
Console.WriteLine(MyBase.Field)
Console.WriteLine(Field)
End Sub
End Class
Module Sample
Public Sub Main()
Dim i As New DerivedClass()
i.Print()
End Sub
End Module
42 3
VBのMyBaseキーワードはC#におけるbase
にほぼ相当するものです。
My名前空間
VBではMe・MyClass・MyBaseの他にも似た名前を持つもとしてMy名前空間といものが存在します。 My名前空間はVB8(VB2005)から導入されたもので、様々な機能や情報へのショートカットを提供するものです。 そのため、Me・MyClass・MyBaseの各キーワードとMy名前空間は全く役割が異なります。
Module Sample
Public Sub Main()
' 現在ログインしているユーザの名前を取得する
Console.WriteLine(My.User.Name)
' コンピュータの名前を取得する
Console.WriteLine(My.Computer.Name)
' ファイルが存在しているか調べる
Dim file As String = "E:\sample.txt"
If My.Computer.FileSystem.FileExists(file)
Console.WriteLine("ファイル{0}は存在します", file)
Else
Console.WriteLine("ファイル{0}は存在しません", file)
End If
End Sub
End Module
My名前空間についてはMy名前空間をご覧ください。