|
|
連載
改訂版
プロフェッショナルVB.NETプログラミング
Chapter 05 オブジェクト関連の変化
株式会社ピーデー
川俣 晶
2004/04/15 |
|
|
クラスの中で、Sharedキーワードを付けたメンバは、インスタンスが作成されなくても存在し、インスタンスの数と関係なく実体は1つだけ存在する。このメンバを初期化するために、共有コンストラクタという機能がある。リスト5-35はそれを利用した例である(Sharedキーワードについては、インスタンスを作成せずに呼び出せるメソッドも参照)。
1: Public Class A
2: Private Shared a(9) As String
3:
4: Shared Sub New()
5: Dim i As Integer
6: For i = 0 To 9
7: a(i) = "オフ"
8: Next
9: End Sub
10:
11: Public Shared Sub TurnOn(ByVal index As Integer)
12: a(index) = "オン"
13: End Sub
14:
15: Public Shared Sub Dump()
16: Dim i As Integer
17: For i = 0 To 9
18: Trace.WriteLine(a(i))
19: Next
20: End Sub
21: End Class
22:
23: Public Class Form1
24: Inherits System.Windows.Forms.Form
25:
26: …Windows フォーム デザイナで生成されたコード…
27:
28: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
29: A.TurnOn(2)
30: A.TurnOn(5)
31: A.TurnOn(7)
32: A.Dump()
33: End Sub
34: End Class
|
|
リスト5-35 共有されるメンバを初期化するために共有コンストラクタを使用したプログラム
|
これを実行すると以下のようになる。
1: オフ
2: オフ
3: オン
4: オフ
5: オフ
6: オン
7: オフ
8: オン
9: オフ
10: オフ
|
|
リスト5-36 リスト5-35の実行結果
|
このソースの中で、4〜9行目が共有コンストラクタである。Sharedキーワードが共有コンストラクタであることを示している。この共有コンストラクタを呼び出すコードはどこにも記述されていない。しかし、共有されるメンバを参照する前に、自動的にこのコンストラクタは呼び出される。共有されるメンバを活用する場合には、便利な機能である。
VB 6では、既定のメソッドやプロパティを持つことができる。これは、インスタンスだけを指定した場合に指定されたと見なされるメソッドやプロパティのことである。例えば、フォーム上のテキストボックスに文字列を代入するときは、
TextBox1.Text = "Hello!"
のように記述するが、Textプロパティは既定のプロパティであるため、.Textを省いて、
TextBox1 = "Hello!"
と書いても等価である。
では、実際にそういうサンプル・プログラムを記述してみよう。まず、以下のようなプロパティを持つクラス・モジュールを書いてみた。
1: Private str As String
2:
3: Public Property Get test1() As String
4: test1 = str
5: End Property
6:
7: Public Property Let test1(s As String)
8: str = s
9: End Property
|
|
リスト5-37 プロパティtest1を持つクラスを定義したプログラム
|
次に、[ツール]メニューの[プロシージャ属性]を選んで、[詳細]ボタンを押し、名前test1に対応する[プロシージャID]を「(既定値)」に変更する。
|
●図5-38 VB 6の[プロシージャ属性]ダイアログ |
これで、プロパティtest1は既定のプロパティになったので、リスト5-39のようなコードを記述できるようになる。
1: Private Sub Form_Load()
2: Dim a As New Class1
3: a = "Hello!"
4: Debug.Print a
5: a.test1 = "World!"
6: Debug.Print a.test1
7: End Sub
|
|
リスト5-39 既定のプロパティとして設定したプロパティtest1を使用したプログラム
|
これを実行すると以下のようになる。
|
リスト5-40 リスト5-39の実行結果
|
では、これに相当するプログラムがVB.NETで書けるだろうか。答えは「書けない」である。VB.NETには、既定のプロパティやメソッドは存在しないのである。なお、例外的に、引数のあるプロパティを既定のプロパティとして指定することはできる(引数を持つ既定のプロパティを参照)。
なるべくこれに近いサンプル・プログラムを書いてみよう。まずは、クラス・モジュールから。
1: Public Class Class1
2: Private str As String
3:
4: Public Property test1() As String
5: Get
6: Return str
7: End Get
8: Set(ByVal Value As String)
9: str = Value
10: End Set
11: End Property
12: End Class
|
|
リスト5-41 リスト5-37をVB.NETで書き換えたプログラム
|
これを呼び出すプログラムは、リスト5-42のようになる。Class1型変数への代入はエラーになるので、プロパティ名は明示的に書き込まねばならない。だが、Trace.WriteLineメソッドに渡す場合、Class1型のままでもコンパイルエラーにはならない。これは、そのまま残してみよう。
1: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
2: Dim a As New Class1()
3: a.test1 = "Hello!"
4: Trace.WriteLine(a)
5: a.test1 = "World!"
6: Trace.WriteLine(a.test1)
7: End Sub
|
|
リスト5-42 リスト5-41のプロパティを使用したプログラム
|
これを実行すると、以下のようになる。
1: Sample002o2.Class1
2: World!
|
|
リスト5-43 リスト5-42の実行結果
|
見てのとおり、4行目のTrace.WriteLine(a)は、まったく無関係の文字列が出力されており、似ても似つかない。この文字列は名前空間を含むクラスのフルネームである。クラスは、特に設定しない限り、Trace.WriteLineメソッドの引数に渡されるとフルネームを出力する。
さて、このとき出力される文字列は、ある方法でカスタマイズできる。つまり、非常に限定された状況でのみ、既定のプロパティがあるかのように振る舞わせることができる。リスト5-44はそれを実際に試してみた例である。
そのためには、クラス・モジュールにToStringというメソッドを追加する。
1: Public Class Class1
2: Private str As String
3:
4: Public Property test1() As String
5: Get
6: Return str
7: End Get
8: Set(ByVal Value As String)
9: str = Value
10: End Set
11: End Property
12:
13: Public Overrides Function ToString() As String
14: ToString = str
15: End Function
16: End Class
|
|
リスト5-44 既定のプロパティがあるかのように振る舞わせたプログラム
|
呼び出す側のコードの変更はない(リスト5-42と同じ)。これを実行すると以下のようになる。
|
リスト5-45 リスト5-44の実行結果
|
ここでポイントになるのは、ToStringメソッドである。コード13行目を見て分かるとおり、Overridesキーワードを使って、ToStringメソッドの内容を入れ替えている(Overridesキーワードについては、Overridesキーワードを使って継承時にメソッドの動作を入れ替えるを参照)。だが、このコードにToStringメソッドは1回しか出現しない。内容を入れ替えるなら、2回以上ToStringメソッドの定義がなければならないし、さらに使われているのなら、コードのどこかにToStringメソッドの呼び出しがなければならない。これはどうしたことだろうか?
まず、すべてのクラスは暗黙的にSystem.Objectというクラスを継承しているという事実がある。そして、System.Objectには、ToStringというメソッドが含まれている。このメソッドを置き換えるコードが、このコードの13〜15行目というわけである。そして、第2のポイントは、Trace.WriteLineメソッドは、引数の値を出力可能な文字列に変換するために、このToStringメソッドを呼び出すことである。つまり、クラスのToStringメソッドを記述すれば、Trace.WriteLineメソッドで出力される内容を自由にコントロール可能というわけである。そのほか、ToStringメソッドは、あらゆるオブジェクトを文字列に変換するために利用される定番のメソッドであるため、これを実装しておく価値は大きい。しかし、これは既定のプロパティとはまったく別個の機能であることに注意が必要である。