連載

改訂版
プロフェッショナルVB.NETプログラミング

Chapter 05 オブジェクト関連の変化

株式会社ピーデー 川俣 晶
2004/04/15
Page1 Page2 Page3 Page4


 本記事は、(株)技術評論社が発行する書籍『VB6プログラマーのための入門 Visual Basic .NET 独習講座』の一部分を許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

インターフェイス機能の変更点

 VB 6には、継承はなくてもインターフェイスの機能があり、簡単なポリモーフィズムぐらいなら記述することができた。しかし、このインターフェイス関係の機能が、VB 6とVB.NETでは大幅に変化している。その実例を見てみよう。

 ここでは、クラス1個、インターフェイス1個を持つサンプル・プログラムを記述してから、インターフェイス経由で、クラス内に記述したメソッドを呼び出してみる。まずは、インターフェイス「Class2」を定義したソースである。

1: Public Sub OutputMessage(ByVal msg As String)
2: End Sub
リスト5-18 インターフェイス「Class2」を定義したプログラム

 次に、このインターフェイスを実装するクラス「Class1」を記述してみた。

1: Implements Class2
2: Public Sub Class2_OutputMessage(ByVal msg As String)
3:   Debug.Print msg
4: End Sub
リスト5-19 リスト5-18のインターフェイスを実装したクラス「Class1」

 これらを利用した、インターフェイス経由でクラスのメソッドを呼び出すソース・コードとして以下のようなものを書いてみた。

1: Private Sub Form_Load()
2:   Dim obj As Class1
3:   Set obj = New Class1
4:   Dim interf As Class2
5:   Set interf = obj
6:   interf.OutputMessage "Hello!"
7: End Sub
リスト5-20 インターフェイス経由でクラスのメソッドを呼び出すプログラム

 これを実行すると以下のような出力が得られる。そのことに疑問はないと思う。

1: Hello!
リスト5-21 リスト5-20の実行結果

 さて、このソースをVB.NET用に書き換えるにはどうすればよいのだろうか。1つずつソースを置き換えてみよう。まず、インターフェイスの定義は以下のようになる。

1: Public Interface Class2
2:   Sub OutputMessage(ByVal msg As String)
3: End Interface
リスト5-22 インターフェイスを定義しているリスト5-18をVB.NETで書き換えたプログラム

 見てのとおり、相当違っていることが分かるだろう。まず、VB 6ではインターフェイスはクラスの一種として作成したが、VB.NETではインターフェイスはインターフェイスという機能として扱われている。そのため、1行目のように“Interface”で始めて、3行目のように“End Interface”で終わる必要がある。そして、肝心の中身の定義も大きく異なっている。VB 6では中身のないSubを記述することでインターフェイスのメンバを定義したが、VB.NETでは最初から中身がないものとして扱われる。これは、最初に1行目でインターフェイスであることを明示していることにより、中身が存在しないことが明らかだからである。その結果、中身の終わりを示すEnd Subを記述する必要はなく、実際、上記のソースにはEnd Subが含まれない。

 もう1点の相違は、Subの手前に付いていたPublicキーワードが、VB.NETでは不要になったことだ。インターフェイスでは、Privateにすることに意味がないので、Publicキーワードをわざわざ付ける意味はない。もし、インターフェイスにPrivateな定義が含まれていたとしても、それをほかのクラスなどから参照できないため、実装することができないのである。

 なお、ここではVB 6のソースに合わせて「Class2」という名前でインターフェイスを作成しているが、これはVB.NETらしいネーミングとしてはそぐわない。例えば、「Interface2」というような名前の方が適切だろう。

 さて、次は、このインターフェイスを実装するクラスのサンプル・プログラムである(リスト5-23)。

1: Public Class Class1
2:   Implements Class2
3:   Public Sub OutputMessage(ByVal msg As String) Implements Class2.OutputMessage
4:     Trace.WriteLine(msg)
5:   End Sub
6: End Class
リスト5-23 リスト5-22のインターフェイスを実装するプログラム

 注目してもらいたいのは3行目で、ここでインターフェイスで定義されたメソッドの内容を実装している。その際、VB 6では、クラス名とメソッド名を含む独特の名前を用いて、インターフェイスの実装であることを示していた。今回のサンプルなら、インターフェイスのクラス名がClass2で、メソッド名がOutputMessageであるため、Class2_OutputMessageという名前のメソッドを記述していた。しかし、VB.NETではそのようなネーミングを使用せず、その代わりにImplementsキーワードを使う。Implementsキーワードの後に、インターフェイス名とメソッド名をピリオド区切りで記述する。これは、名前空間名を含む長い名前であってもよい。これにより、どのインターフェイスのどのメソッドを実装するのかが明示される。

 最後に、これらのソースを呼び出す側のコードを以下に示す(リスト5-24)。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Dim obj As Class1
3:   obj = New Class1()
4:   Dim interf As Class2
5:   interf = obj
6:   interf.OutputMessage("Hello!")
7: End Sub
リスト5-24 リスト5-23を利用するプログラム

 これを実行すると以下のようになる。

1: Hello!
リスト5-25 リスト5-24の実行結果

 インターフェイスの定義と実装は変わったが、利用する方法は変わってはいないことが分かるだろう。

プロパティ構文の変更

 VB 6からVB.NETで変化したものは多いが、プロパティの構文は、特に大きな変更があったポイントの1つといえるだろう。事前の知識がなければ、どう書き換えればよいのか、予測もつかないはずだ。それぐらい劇的に変化している。では、最初にVB 6でプロパティを記述した例を以下に示そう。まず、2つのプロパティを持つクラスのコードから(リスト5-26)。

 1: Private str As String
 2: Private obj As Object
 3:
 4: Public Property Get test1() As String
 5:   test1 = "Hello World!"
 6: End Property
 7:
 8: Public Property Let test1(s As String)
 9:   str = s
10: End Property
11:
12: Public Property Get test2() As Object
13:   Set test2 = obj
14: End Property
15:
16: Public Property Set test2(o As Object)
17:   Set obj = o
18: End Property
リスト5-26 2つのプロパティを持つクラスを定義したプログラム

 これを呼び出すコードとして、以下のようなコードを記述してみた(リスト5-27)。

1: Private Sub Form_Load()
2:   Dim obj As New Class1
3:
4:   obj.test1 = "Hello!"
5:   Debug.Print obj.test1
6:
7:   Set obj.test2 = Form1
8:   Debug.Print obj.test2.Caption
9: End Sub
リスト5-27 リスト5-26を呼び出すプログラム

 これを実行すると以下のようになる。

1: Hello World!
2: Form1
リスト5-28 リスト5-27の実行結果

 では、これとほぼ同等の機能をVB.NETで記述してみた例を次に示す。まずは、プロパティを持つクラスのソースから(リスト5-29)。

 1: Public Class Class1
 2:   Private str As String
 3:   Private obj As Object
 4:
 5:   Public Property test1() As String
 6:     Get
 7:       Return str
 8:     End Get
 9:     Set(ByVal Value As String)
10:       str = Value
11:     End Set
12:   End Property
13:
14:   Public Property test2() As Object
15:     Get
16:       Return obj
17:     End Get
18:     Set(ByVal Value As Object)
19:       obj = Value
20:     End Set
21:   End Property
22: End Class
リスト5-29 リスト5-26とほぼ同等の機能を持つVB.NETのプログラム

 見てのとおり、激変である。まず、Property Set、Property Let、Property Getの3つの構文は姿を消した。その代わり、5行目や14行目のようなProperty宣言を用いて、プロパティの宣言を行う。そして、Property宣言の内部に、“Get〜End Get”と“Set〜End Set”を書き込んで、その中に実際にSetやGetの処理を書き込む。ここで注意すべきことは、VB 6では、Set、Let、Getと3つの種類の操作があったのに、VB.NETには、SetとGetしか存在しないことである。これは、VB.NETではLetとSetの区別がなくなったことにより、プロパティでも、LetとSetの区別が不要になったことによる変化である。

 実際にプロパティの動作を記述する方法も変化している。まず、7行目や16行目のReturnは、プロパティの値を設定する機能を持っている。Returnを使うのは、メソッドの戻り値を指定するためのVB.NETの新しい構文と共通のものである(プロシージャ脱出とReturnステートメント関数の戻り値とReturnステートメントを参照)。なお、従来どおり、プロパティ名への代入で行うこともできる。

 これを呼び出すコードは、リスト5-30のようになる。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Dim obj As New Class1()
3:
4:   obj.test1 = "Hello!"
5:   Trace.WriteLine(obj.test1)
6:
7:   obj.test2 = sender
8:   Trace.WriteLine(obj.test2.Text)
9: End Sub
リスト5-30 リスト5-29を呼び出すプログラム

 ほとんど同じだが、Setキーワードが不要になり、SetとLetの区別が不要になったことが、このソースからも読みとれるだろう。なお、7行目だけ別のコードに書き変わっているが、VB 6のForm1はフォームのインスタンスの名前であるのに対して、VB.NETではForm1はクラス名であることにより、Form1を代入することはできない。このイベントが発生したフォームのインスタンスへの参照は、Loadイベントの引数のsenderに含まれているので、これを使えば等価の結果となる。さらに、8行目のTextプロパティは、VB 6のCaptionプロパティの名前が変わったものである。

 これを実行すると、以下のようになる。

1: Hello!
2: Form1
リスト5-31 リスト5-30の実行結果

 結果は同じだが、構文は大きく変わったので注意しよう。

インスタンスを作成せずに呼び出せるメソッド

 VB 6には、厳密にぴったり対応する機能が見あたらないのだが(しいていえば、Moduleに含まれるメソッドなどに近い)、VB.NETには、インスタンスを作成せずに呼び出せるメソッドを記述できる。リスト5-32はそれを記述したサンプル・プログラムである。

1: Public Class Class1
2:   Public Shared Sub TestShare()
3:     Trace.WriteLine("TestShare called")
4:   End Sub
5:
6:   Public Sub TestNonShare()
7:     Trace.WriteLine("TestNonShare called")
8:   End Sub
9: End Class
リスト5-32 Sharedキーワードを使用してメソッドを定義したプログラム

 このソース・コードの2行目を見ていただきたい。Subキーワードの手前に、Sharedというキーワードが見えると思うが、これがインスタンスを作成せずに呼び出せるメソッドであることを示している。これを共有メソッドという。対比のために、6〜8行目に、通常のメソッドも記述してみた。

 このクラスを利用するサンプル・プログラムを以下のように記述してみた(リスト5-33)。

1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2:   Class1.TestShare()
3:   Dim instance As New Class1()
4:   instance.TestNonShare()
5:   instance.TestShare()
6: End Sub
リスト5-33 リスト5-32を利用するプログラム

 これを実行すると以下のようになる。

1: TestShare called
2: TestNonShare called
3: TestShare called
リスト5-34 リスト5-33の実行結果

 見てのとおり、3行目のDim文でインスタンスを作成する前に、2行目でClass1のTestShareメソッドが呼び出されている。Class1.TestShare()という記述で分かるとおり、このような場合には、インスタンスではなくクラス名を明示する。

 しかし5行目のように、インスタンスの名前を明示して、それを経由して共有メソッドを呼び出すこともできる。

 なお、当たり前のことではあるが、共有メソッドはインスタンスを作成せずに呼び出せることから分かるとおり、インスタンスに属するメンバ変数などにアクセスすることはできない。

 Sharedキーワードはメソッドだけでなく、メンバ変数など他のクラスの構成要素にも付加することができる。コンストラクタに付けた場合は、共有コンストラクタで解説している。


 INDEX
  [連載] 改訂版 プロフェッショナルVB.NETプログラミング
  Chapter 05 オブジェクト関連の変化
    1.オブジェクト生成と解放のタイミングの違い/オーバーロード/コンストラクタへの引数
  2.インターフェイス機能の変更点/プロパティ構文の変更/インスタンスを作成せずに呼び出せるメソッド
    3.共有コンストラクタ/既定のプロパティ
    4.引数を持つ既定のプロパティ/Disposeパターン/Instancingプロパティの変更
 
「改訂版 プロフェッショナルVB.NETプログラミング 」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH