【テクニカル・上級編】モーダルダイアログの戻り値(DialogResult)をカスタムオブジェクト経由で拡張し、呼び出し元へリッチなデータを返す設計パターン – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

Windows Formsの限界を突破せよ:DialogResultを超越する「カスタム結果オブジェクト」の実装戦略

業務システムのUI開発において、`DialogResult`列挙型による「OKかキャンセルか」という二元論に甘んじていないだろうか。

シニアエンジニアであれば一度は直面するはずだ。モーダルダイアログで複雑なエンティティ編集を行い、その結果として「更新されたレコードのID」「後続処理に必要なステータスフラグ」「ログ出力用オブジェクト」のすべてを呼び出し元へ安全に伝えたいという欲求に。

本稿では、標準の `DialogResult` の制約を打破し、メモリ効率と型安全性を両立した「カスタム結果オブジェクト」によるデータ引き渡しパターンを伝授する。

—

なぜDialogResultだけでは不十分なのか

`DialogResult` はあくまでUIの終了ステータスを通知するためのフラグに過ぎない。ここに無理やり文字列を詰め込んだり、親フォームのプロパティを直接操作(いわゆる「密結合な呼び出し」)するのは悪手だ。

メモリリークや予期せぬ例外を回避し、堅牢なシステムを構築するには、「ダイアログは自身の結果をカプセル化した『Resultオブジェクト』を保持し、呼び出し元はそのインスタンスを安全に取得する」という設計が不可欠である。

—

実装パターン:Resultクラスによるデータカプセル化

まずは、ダイアログの結果を格納するための専用クラスを定義する。

”’

”’ ダイアログから返却される詳細データを持つコンテナ
”’ 構造体ではなくクラスを用いることで、参照の受け渡しを明確にする
”’

Public Class EditorDialogResult
Public Property ResultStatus As DialogResult
Public Property UpdatedId As Integer
Public Property ExecutionLog As String
Public Property IsSuccess As Boolean
End Class

次に、ダイアログ側での実装だ。ここで重要なのは、呼び出し元にプロパティを公開し、オブジェクトの生存期間を適切に管理することである。

Public Class MyDetailDialog
Inherits Form

‘ 結果を保持するプロパティを定義
Public Property ResultData As EditorDialogResult

Private Sub btnOk_Click(sender As Object, e As EventArgs) Handles btnOk.Click
‘ 終了前に結果オブジェクトを生成・設定
Me.ResultData = New EditorDialogResult With {
.ResultStatus = DialogResult.OK,
.UpdatedId = 12345,
.ExecutionLog = “DB更新成功: タイムスタンプ ” & DateTime.Now.ToString(),
.IsSuccess = True
}

Me.DialogResult = DialogResult.OK
Me.Close()
End Sub
End Class

—

呼び出し元でのハンドリングとメモリ管理の極意

呼び出し元(親フォーム)では、`Using`ステートメントを使用してダイアログのライフサイクルを厳密に管理する。これにより、メモリの解放漏れを防ぎ、不要なオブジェクトがGC(ガベージコレクション)へ適切に回収されることを保証する。

Private Sub OpenDetailDialog()
‘ Using句でスコープを限定し、メモリの即時解放を促す
Using dlg As New MyDetailDialog()
If dlg.ShowDialog() = DialogResult.OK Then
‘ ダイアログがDisposeされる前に、必要なデータを取り出す
Dim info As EditorDialogResult = dlg.ResultData

If info IsNot Nothing AndAlso info.IsSuccess Then
Console.WriteLine($”更新されたID: {info.UpdatedId}”)
Console.WriteLine($”ログ: {info.ExecutionLog}”)
End If
End If
End Using
End Sub

—

シニアエンジニアが意識すべき「裏側の挙動」

この設計には、単なるコードの綺麗さ以上の意味がある。

1. 型の安全性(Type Safety):
`Tag` プロパティに `Object` 型で何でも詰め込む手法は論外だ。カスタムクラスを用いることで、コンパイル時に型の不整合を検知できる。
2. Disposeパターンの遵守:
Windows Formsのダイアログは `IDisposable` を実装している。`Using` を忘れることは、GDIリソースの枯渇を招き、長時間の稼働でアプリケーションが不安定になる原因となる。
3. システム間連携への拡張性:
この `EditorDialogResult` は、将来的にJSONシリアライズしてWeb API経由で別システムへ渡す、といった拡張も容易だ。設計の抽象度を上げておくことは、保守性を担保するための唯一の解である。

結論:型を信じ、メモリを制御せよ

VB.NETは、その冗長な構文ゆえに「レガシー」と揶揄されることもある。しかし、その裏でメモリをどう扱い、オブジェクトがどのように生成・消滅するかを制御するアーキテクチャの視点さえあれば、モダンな環境下でも驚くほど高性能なUIを実現できる。

`DialogResult` という小さな列挙型に縛られるな。我々が制御すべきは、システムを流れる「データ」そのものである。

次に貴殿がダイアログを設計する際、この「カスタム結果オブジェクト」を導入してみてほしい。チームのコード品質が、また一つ上の階層へ押し上げられるはずだ。

タイトルとURLをコピーしました