Meはクラスや構造体のインスタンス自身を参照するためのキーワードです。 MyClassもインスタンス自身のメンバを参照する点はMeと同じですが、呼び出そうとするメソッドがオーバーライドされていてもMyClassが使われたクラスの実装が呼び出されるという点がMeとは異なります。 MyClassは自クラスのメンバを参照する場合に使用するのに対して、MyBaseは基底クラスのメンバを参照する際に使用します。

この他にもMe・MyClass・MyBaseとは役割は異なるものの似た名前を持つものとしてMy名前空間というものも存在します。

MeとMyClass

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を明記する必要があります。

隠蔽されたメンバの参照

メソッドがクラスや構造体のフィールド(メンバ変数)と同名の引数をとる場合、そのメソッド内では同名のメンバは隠蔽されます。 次の例では、コンストラクタの引数にxyがあり、この引数が同名のフィールドxy隠蔽します。 そのため、xyはインスタンスのフィールドではなくコンストラクタの引数xyを表すことになります。 この例において、引数xyの値はフィールドには代入されず、意図したとおりには初期化されません。

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が使用されたクラスのメソッドが呼び出されます。

Meと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の使い分けを整理すると次のようになります。

  1. インスタンス自身を引数として渡す場合はMe
  2. オーバーライドを無視して自クラスのメソッドの呼び出しを行う場合はMyClass
  3. オーバーライドされないメンバや隠蔽されたメンバを参照する場合は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名前空間は全く役割が異なります。

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名前空間をご覧ください。