VB.NETのモーダルダイアログを「最強のデータ搬送装置」に変える設計術
多くのVB.NET開発者が、モーダルダイアログから値を戻す際に「グローバル変数」や「Publicなプロパティへの直接参照」という悪魔の誘惑に負けている。
「とりあえず動けばいい」という考えで書かれたコードは、数ヶ月後のメンテナンスで必ず牙を剥く。呼び出し元と呼び出し先の密結合(Tight Coupling)は、バグの温床であり、ユニットテストを不可能にする最大の要因だ。
今日は、プロとして現場で通用する、「カスタムオブジェクト経由でリッチなデータを安全に返す」ための設計パターンを伝授する。
—
1. なぜ「DialogResult」だけでは足りないのか
標準の `DialogResult` は、単なる「OK」か「キャンセル」かのフラグに過ぎない。しかし、業務システムの実務では、「どの顧客を選んだか」「どのパラメータで処理を実行するか」「入力されたバリデーション結果はどうだったか」といった、構造化されたデータが必要になる。
これを実現するために、フォーム自体をデータコンテナとして汚染させるのではなく、「結果格納用クラス(DTO: Data Transfer Object)」を介在させるのが、堅牢なシステム設計の基本だ。
—
2. 実装パターン:Resultクラスを用いた疎結合設計
このパターンでは、呼び出し先(子フォーム)で生成した結果オブジェクトを、呼び出し元(親フォーム)が受け取る。
手順①:結果格納用クラスの定義
まずは、受け渡し専用のクラスを作る。これは単なるデータの箱だ。
”’
”’
Public Class CustomerSelectionResult
Public Property CustomerId As Integer
Public Property SelectedName As String
Public Property IsValidated As Boolean
‘ 必要に応じて複雑なオブジェクトやリストも保持可能
End Class
手順②:子フォーム(ダイアログ)の実装
子フォームは「自分の結果を自分で用意する」という責任を持つ。
Public Class CustomerSelectForm
‘ 結果を保持するプロパティ(初期値はNothing)
Public Property ResultData As CustomerSelectionResult
Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
‘ データの構築とバリデーション
If Not ValidateInputs() Then Return
‘ 結果オブジェクトの生成
ResultData = New CustomerSelectionResult With {
.CustomerId = CInt(txtId.Text),
.SelectedName = txtName.Text,
.IsValidated = True
}
‘ 正常終了を通知
Me.DialogResult = DialogResult.OK
Me.Close()
End Sub
End Class
手順③:呼び出し元(親フォーム)の実装
親フォームは、子フォームが閉じられた直後に `ResultData` を安全に取り出す。
Private Sub btnOpenDialog_Click(sender As Object, e As EventArgs) Handles btnOpenDialog.Click
Using dlg As New CustomerSelectForm()
If dlg.ShowDialog() = DialogResult.OK Then
‘ ここで安全にデータを回収する
Dim res = dlg.ResultData
If res IsNot Nothing Then
Console.WriteLine($”選択された顧客: {res.SelectedName} (ID: {res.CustomerId})”)
‘ ここからDB更新やファイル出力処理へ繋げる
End If
End If
End Using ‘ Usingブロックで確実にメモリ解放
End Sub
—
3. 現場で「バグらせない」ための3つの極意
① Using ステートメントを徹底せよ
Windows Formsにおいて、フォームは `IDisposable` を継承している。`ShowDialog()` を呼ぶ際は、必ず `Using` ブロックで囲むこと。これを怠ると、特に画像やDB接続を含むフォームで、メモリリークやハンドル不足による不可解なクラッシュが発生する。
② 不変性(Immutability)を意識する
もし可能であれば、`ResultData` のプロパティを `ReadOnly` にし、コンストラクタ経由で値をセットするように設計すれば、データが途中で書き換えられるリスクをゼロにできる。
③ 戻り値のNullチェックを怠るな
`DialogResult.OK` が返ってきたとしても、何らかの理由で `ResultData` がセットされていない可能性を考慮せよ。「呼び出し元で `Nothing` チェックを行わない」のは、実務においては手抜きである。
—
まとめ:アーキテクトからの助言
今回紹介した「DTOを介したデータ受け渡し」は、単なるコードの書き方ではない。「どの部品が何を知っているべきか(関心の分離)」という設計思想そのものだ。
- 子フォームは「どうデータを集めるか」を知っている。
- 呼び出し元は「結果をどう料理するか」を知っている。
- DTOは「データの形」だけを知っている。
この境界線を守るだけで、あなたの書くVB.NETコードは、泥臭いスクリプトから、堅牢で拡張性の高いエンタープライズ・アプリケーションへと変貌を遂げる。
「動けばいい」という次元を卒業し、保守性を愛するエンジニアであれ。健闘を祈る。
