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を省略して単にメンバ名
とします。
構造体の場合も同様にMeでインスタンス自身のメンバを参照できます。
MeではなくMyClassでインスタンス自身のメンバを参照することもできます。
このようにMe・MyClassでインスタンス自身のメンバを参照することを明示できます。 ここまでで紹介した例ではMe・MyClassを省略することもできますが、隠蔽されたメンバを参照する場合はMe・MyClassを明記する必要があります。
隠蔽されたメンバの参照
メソッドがクラスや構造体のフィールド(メンバ変数)と同名の引数をとる場合、そのメソッド内では同名のメンバは隠蔽されます。 次の例では、コンストラクタの引数にx
とy
があり、この引数が同名のフィールドx
とy
を隠蔽します。 そのため、x
とy
はインスタンスのフィールドではなくコンストラクタの引数x
とy
を表すことになります。 この例において、引数x
とy
の値はフィールドには代入されず、意図したとおりには初期化されません。
このように隠蔽されたメンバは存在しなくなるわけではなく、MeまたはMyClassを使うことで隠蔽されたメンバを参照することができます。
引数の場合のほかにも、ローカル変数の場合でも同名のメンバが隠蔽されます。 この場合でも、Me・MyClassを使うことでローカル変数に隠蔽されたメンバを参照することができます。
MeやMyClassを使って隠蔽されたメンバを参照するよりも、メンバ名と同名の引数名・変数名を付けることを避けたほうが分かりやすく、無難です。
コンストラクタの呼び出し
コンストラクタでは、引数の異なる別のコンストラクタを呼び出すことができます。 この場合、メソッド呼び出しのようにコンストラクタを直接New(...)
として呼び出すことはできません。 必ずMeもしくはMyClassを伴ってMe.New(...)
やMyClass.New(...)
のように呼び出す必要があります。
オーバーライドを無視したメソッドの呼び出し
クラスを継承してメソッドをオーバーライドすると、基底クラスのメソッドの動作を変更することができます。 基底クラス内からオーバーライド可能なメソッドを呼び出す場合、派生クラスでメソッドがオーバーライドされていれば、そのメソッドが呼び出されます。
MeおよびMyClassを使ってオーバーライドされているメソッドを呼び出す場合、両者は同じ動作とはならない点に注意が必要です。 Meキーワードでオーバーライドされているメソッドを呼び出す場合は、Meを省略して呼び出した場合と同じく派生クラスでオーバーライドされた方のメソッドが呼び出されますが、MyClassキーワードではMyClassが使用されたクラスのメソッドが呼び出されます。
Meではメソッドのオーバーライドが有効になるのに対し、MyClassではオーバーライドが無視されると見ることができます。 言い換えると、Meではオーバーライドの影響を受けるのに対し、MyClassではオーバーライドの影響を受けない、となります。
もしくは、Meではインスタンス自身(=Me)が派生クラスかどうかを考慮してメソッド呼び出しを行うのに対し、MyClassでは常に自分のクラス(=MyClass)のメソッドを呼び出すと見ることもできます。
なお、コンストラクタ(Newメソッド)も一種のメソッドとみなされますが、コンストラクタはオーバーライドできないためMeとMyClassのどちらを使って呼び出しても動作が変わることはありません。
インスタンス自身の引渡し
RaiseEventによってイベントを発生させる場合や、メソッドの引数としてインスタンス自身を渡す場合にはMeを使います。 MyClassではインスタンス自身を引き渡すことはできません。
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を明記して呼び出す必要があります。
コンストラクタから基底クラスのコンストラクタを呼び出す場合も、MyBaseを明記します。
派生クラスで基底クラスと同名のフィールドを宣言した場合も、基底クラス側のフィールドが隠蔽されます。 隠蔽された基底クラスのフィールドを参照する場合にもMyBaseを明記します。
VBのMyBaseキーワードはC#におけるbase
にほぼ相当するものです。
My名前空間
VBではMe・MyClass・MyBaseの他にも似た名前を持つもとしてMy名前空間といものが存在します。 My名前空間はVB8(VB2005)から導入されたもので、様々な機能や情報へのショートカットを提供するものです。 そのため、Me・MyClass・MyBaseの各キーワードとMy名前空間は全く役割が異なります。
My名前空間についてはMy名前空間をご覧ください。