泥沼のUI制御を脱却せよ:AddressOfとAddHandlerが導く「疎結合」という解法
業務システムの現場において、画面上のコントロールを動的に生成・配置するケースは避けて通れない。特に、数百の入力フィールドや動的なテーブルを扱う際、デザイナで一つ一つイベントを紐付けるのは「技術的負債」の温床だ。
VB.NETのデリゲート(Delegate)の概念を理解せず、ただコードを書き散らす者は、いつか必ずメモリリークと循環参照の罠に落ちる。今日は、`AddressOf`演算子と`AddHandler`を武器に、堅牢でメモリ効率の良いUI構築術を伝授する。
—
1. AddressOfの本質:関数を「値」として扱うということ
`AddressOf`は、単なる「メソッドの場所を指すもの」ではない。それは、メソッドをインスタンス化可能なオブジェクト(デリゲート)として抽出する操作だ。
.net
‘ AddressOf を使って、メソッドをデリゲートとして抽出する
Dim handler As EventHandler = AddressOf OnDynamicButtonClicked
この一行の意味を深く理解せよ。これは、メソッドのメモリ上のアドレスを取得し、それをイベントの「購読リスト」に登録するためのチケットを発行しているに過ぎない。このチケットを適切に管理しないと、GC(ガベージコレクション)が回収不能なメモリの残骸が生まれる。
—
2. AddHandlerによる動的バインドの極意
`AddHandler`は、実行時にイベントソースとハンドラを結合する。ここで重要なのは、「いつ紐付け、いつ解除するか」だ。
実践:メモリリークを防ぐ動的コントロール配置
.net
Public Class DynamicFormManager
Private Sub CreateDynamicControls()
Dim btn As New Button() With {.Name = “btnDynamic”, .Text = “実行”}
‘ イベントハンドラを動的に付与
AddHandler btn.Click, AddressOf HandleDynamicClick
Me.Controls.Add(btn)
End Sub
Private Sub HandleDynamicClick(sender As Object, e As EventArgs)
‘ sender をキャストして対象を特定。UIのID管理で混乱を避ける
Dim btn = DirectCast(sender, Button)
MessageBox.Show($”{btn.Name} がクリックされました。”)
End Sub
‘ 【重要】フォーム終了時やコントロール削除時には必ずRemoveHandlerを行う
‘ これを怠ると、UIコンポーネントがメモリ上に残り続け、アプリの肥大化を招く
Private Sub CleanupControls(btn As Button)
RemoveHandler btn.Click, AddressOf HandleDynamicClick
btn.Dispose()
End Sub
End Class
なぜ `RemoveHandler` が重要なのか?
.NETにおいて、イベントハンドラは「強い参照」を保持する。つまり、イベントを紐付けたままコントロールを破棄しようとしても、マネージドヒープ上では「まだ誰かがこのインスタンスを使っている」とみなされ、GCが回収を諦める。長期間稼働する業務端末でこのリークが発生すれば、数日でメモリ不足に陥る。これはアーキテクトとしては「恥」である。
—
3. シニアのための深掘り:Windows APIとの協調
時として、.NETのフレームワークだけでは力不足な場面がある。例えば、特定のウィンドウメッセージをフックする場合などだ。`AddressOf`は、`P/Invoke`によるWin32 APIのコールバック関数を定義する際にも必須となる。
.net
‘ Win32 API: EnumWindows のコールバック定義
Private Delegate Function EnumWindowsProc(hWnd As IntPtr, lParam As IntPtr) As Boolean
‘ API呼び出し
Private Shared Function EnumWindows(lpEnumFunc As EnumWindowsProc, lParam As IntPtr) As Boolean
End Function
‘ コールバックの実装
Private Function MyEnumWindowsHandler(hWnd As IntPtr, lParam As IntPtr) As Boolean
‘ ここでWindowsの全ウィンドウハンドルを走査し、独自の管理リストを構築する
Return True
End Function
このように、`AddressOf`を使えば、VB.NETの作法を超えてOSネイティブのイベントループにすら介入できる。これが「伝説的なエンジニア」がVB.NETを使い続ける理由だ。
—
4. アーキテクトからの提言
若手エンジニアは、IDEの自動生成コードに甘えがちだ。しかし、真に安定したシステムを構築したいのであれば、以下の原則を胸に刻んでほしい。
1. AddHandlerしたなら、必ずRemoveHandlerせよ: メモリのライフサイクルは自分で制御する。
2. Senderを信じろ: 複数のコントロールで一つのハンドラを共有し、`DirectCast`で処理を分岐させる。これが最も保守性の高いコードだ。
3. レガシーを恐れるな: VB.NETのこうした構文は、現在のC#と比較しても遜色ない強力なメモリ管理能力を持っている。道具のせいにせず、仕組みを理解せよ。
`AddressOf`はただの構文ではない。システムとイベントを「接続する」という、エンジニアの意志をコードに宿すための儀式なのだ。この知見を現場に持ち帰り、泥臭く、しかし美しいシステムを築き上げてほしい。
以上。コードが君の背中を語るはずだ。
