C++、VBや、VB.NET、C#にはクラスのインスタンスが自分自身とそのメンバを参照するためのキーワードがあります。 例えばC++ではthisポインタ、VBではMeキーワードなどです。 同様にC#ではthis及びbaseキーワード、VB.NETでは VBから引き続きMeが使われ、新たにMyClassとMyBaseというキーワードが採用されました。 VB.NETとC#でMyBase / baseというキーワードが採用された背景には、共通言語仕様ではクラスの多重継承が認められていないために基底クラスは常に一つであるため、C++のように任意の基底クラスを参照するためにキャストを行う必要がなくなったからと考えられます。

このようにVB.NETとC#の MyClass / this と MyBase / base はその機能や目的は同じであるといえます。 ですが、VB.NETにはMyClassに似た働きを持つMeキーワードが存在します。

Sponsored Link

Me, MyClass, MyBase

Meと MyClassの機能の違いに言及する前に、Me・MyClass・MyBaseを使用した例によってその動作を見てみることにします。

Imports System

' 基底クラス
Public Class BaseClass

    ' 基底クラスでのMethod()
    Protected Overridable Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of BaseClass called by " + keyword)

    End Sub

End Class

' 派生クラス
Public Class DerivedClass
    Inherits BaseClass

    ' 派生クラスでのMethod()
    Protected Overrides Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of DerivedClass called by " + keyword)

    End Sub


    ' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
    Public Sub CallMethods()

        ' MyBase による呼び出し
        MyBase.Method("MyBase")

        ' MyClass による呼び出し
        MyClass.Method("MyClass")

        ' Me による呼び出し
        Me.Method("Me")

    End Sub

End Class

' アプリケーションのエントリーポイント
Module MeMyclassMybase

    Sub Main()

        ' 派生クラスのインスタンスを作成
        Dim inst As New DerivedClass()

        inst.CallMethods()

    End Sub

End Module
実行結果
Method of BaseClass called by MyBase
Method of DerivedClass called by MyClass
Method of DerivedClass called by Me
Press any key to continue

この結果から分かるとおり、MyBaseはそのインスタンスの基底クラスのメンバを参照しているのに対し、MyClass及びMeはそのインスタンス自身のクラスのメンバを参照していることがわかります。 では、MyClassとMeは同じものといえるのでしょうか。 下位互換性のためにMeが残されたのでしょうか。 それともキーワードが二つあるからには何らかの違いがあるのでしょうか。

MeとMyClassの違い

実際のところ、全く意味の同じキーワードが二種類存在するのは下位互換性のためだけではなく、ちゃんとした違いがあります。 ほとんどの機能はMeも MyClassも大差ないのですが、メソッドの呼び出しの時にはその違いがあらわれます。 その違いがあらわれるようなサンプルコードを次に示します。

Imports System

' 基底クラス
Public Class BaseClass

    ' 基底クラスでのMethod()
    Protected Overridable Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of BaseClass called by " + keyword)

    End Sub

    ' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
    Public Sub CallMethods()

        ' MyClass による呼び出し
        MyClass.Method("MyClass")

        ' Me による呼び出し
        Me.Method("Me")

    End Sub

End Class

' 派生クラス
Public Class DerivedClass
    Inherits BaseClass

    ' 派生クラスでのMethod()
    Protected Overrides Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of DerivedClass called by " + keyword)

    End Sub

End Class

' アプリケーションのエントリーポイント
Module MeMyclassMybase

    Sub Main()

        ' 派生クラスのインスタンスを作成
        Dim inst As New DerivedClass()

        inst.CallMethods()

    End Sub

End Module
実行結果
Method of BaseClass called by MyClass
Method of DerivedClass called by Me
Press any key to continue

今回は先ほどとは異なり、CallMethods()を基底クラスに配置しました。 そして、派生クラスDerivedClassのインスタンスを作成し、そのインスタンスからCallMethods()を呼び出しています。 結果を見てわかるとおり、MeとMyClassでは異なる文字列を出力していることがわかります。 つまり、Me.Method()はDerivedClass.Method()を呼び、MyClass.Method()は BaseClass.Method()を呼び出しています。

これは何を意味しているかというと、MyClassはインスタンスのクラスがどのクラスであるかに関わらず、確実にMyClassが用いられたクラスのメソッドを呼び出しているのに対し、Meの場合はMeが用いられたクラスが何であるかに関わらず、インスタンスのクラスのメソッド、つまり派生クラスでオーバーライドされたメソッドを呼び出していることになります。

さらに、派生クラスで基底クラスのメソッドをシャドウするとその挙動は変化します。 次のコードはそれを行ったものです(DerivedClass.Method()のOverridesキーワードをShadowsキーワードに変えています)。

Imports System

' 基底クラス
Public Class BaseClass

    ' 基底クラスでのMethod()
    Protected Overridable Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of BaseClass called by " + keyword)

    End Sub

    ' 各キーワードでインスタンスのメソッドを呼び出すためのメソッド
    Public Sub CallMethods()

        ' MyClass による呼び出し
        MyClass.Method("MyClass")

        ' Me による呼び出し
        Me.Method("Me")

    End Sub

End Class

' 派生クラス
Public Class DerivedClass
    Inherits BaseClass

    ' 派生クラスでのMethod()
    Protected Shadows Sub Method(ByVal keyword As String)

        Console.WriteLine("Method of DerivedClass called by " + keyword)

    End Sub

End Class

' アプリケーションのエントリーポイント
Module MeMyclassMybase

    Sub Main()

        ' 派生クラスのインスタンスを作成
        Dim inst As New DerivedClass()

        inst.CallMethods()

    End Sub

End Module
実行結果
Method of BaseClass called by MyClass
Method of BaseClass called by Me
Press any key to continue

今度はMeもMyClassもBaseClass.Method()を呼び出しています。 このように、メソッドの呼び出しではMeとMyClassは多少挙動が異なるので注意が必要です。 通常の使用方法ならMyClassを用いた方がよけいなバグを生じる可能性は少ないと思います(しかし、VB時代からの習慣で、ついMeを使いたくなってしまいますが・・・)。