【入門編】実務中級者向け:VB.NETにおける「EventHandler(Of T)」を活用した独自イベントの設計と発行:型安全なカスタムイベントの実装 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは!日々、業務システムの自動化や堅牢なアプリケーション開発に奮闘していることと思います。

「Excelマクロの記録から一歩踏み出して、本格的なVB.NETのアプリケーションを作りたい」
「フォームの間やクラスの間で、データを綺麗にやり取りする仕組み(イベント駆動)がいまいちピンと来ない……」

そんな壁にぶつかっていませんか?大丈夫、ここをクリアすれば、あなたのVB.NETスキルは「初心者」から「一人前のエンジニア」へと一気に飛躍します。

今回は、実務で必ず直面する「型安全なカスタムイベントの設計と発行」について、優しく、そして本質的なところまで深く解説していきますね。ここをマスターすれば、VB.NETの基本はバッチリです!

1. なぜ「独自のイベント」と「EventArgsの拡張」が必要なのか?

VB.NETを使っていると、ボタンをクリックしたときの `Click` イベントなど、あらかじめ用意されたイベントをよく扱いますよね。

.net
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
‘ ボタンが押されたときの処理
End Sub

ここで使われている `EventArgs` は、「特に付加的なデータがない時」用の空っぽの箱です。しかし、実際の業務アプリケーションではどうでしょう?

  • 「受注処理が完了した。その時どの受注ID金額が処理されたのかを、別の画面に伝えたい」
  • 「CSVの読み込み中にエラーが発生した。その時の行番号エラーメッセージをログ出力基盤に飛ばしたい」

こういう時、古いコードだと `Object` 型で無理やりデータを渡したり、グローバル変数に値を突っ込んだりしがちです。しかし、それでは「どこでデータが書き換わったか分からない(スパゲッティコード)」の原因になります。

そこで登場するのが、`EventHandler(Of T)` とカスタム `EventArgs` です。これを使うと、「どのデータが流れてくるかがコンパイル時に保証される(=型安全)」モダンで美しいイベント駆動アーキテクチャが実現できます。

2. 実装の全体像:3つのステップ

カスタムイベントを実装するには、以下の3つのステップを踏みます。言葉は難しく聞こえますが、型通りの定石パターンなので、一度覚えてしまえば怖くありません。

1. カスタムデータクラスの作成(`EventArgs`を継承する)
2. イベント発行元クラスの作成(`EventHandler(Of T)` でイベントを定義し、発火させる)
3. イベント購読側(フォームやメイン処理)の作成(イベントを受け取って処理する)

図解的にデータの流れを表すと、以下のようになります。

[ 1. 業務データ (CustomEventArgs) ] を包んで

[ 2. 発行元クラス (Publisher) ] がイベントを発行 (RaiseEvent)

[ 3. 購読側 (Subscriber) ] が安全にデータを受け取って処理を実行

3. 実践!コードで学ぶ型安全なイベント実装

それでは、実際に動くコードを見ていきましょう。今回は「在庫管理システムで、在庫数がしきい値を下回ったときに警告を発する」という実務によくあるシーンを想定します。

ステップ1:独自のイベント引数クラスを作る

まずは、運ぶべきデータ(商品名と残りの在庫数)を定義するクラスを作ります。`EventArgs` を継承するのがお作法です。

.net
Imports System

‘ 1. 業務データを保持するカスタムEventArgs
Public Class LowStockEventArgs
Inherits EventArgs

‘ 読み取り専用プロパティとしてデータを保持させる(カプセル化の基本!)
Public ReadOnly Property ProductName As String
Public ReadOnly Property CurrentStock As Integer

‘ コンストラクタでデータを初期化
Public Sub New(productName As String, currentStock As Integer)
Me.ProductName = productName
Me.CurrentStock = currentStock
End Sub
End Class

> ★先輩からのワンポイントアドバイス:
> プロパティを `ReadOnly` にしておくと、イベントを受け取った側が勝手にデータを書き換えてしまう事故を防げます。データの安全性を守るエンジニアの知恵です。

ステップ2:イベントを発行するクラスを作る

次に、実際に在庫を管理し、条件を満たしたときにイベントを「ドーン!」と発行するクラスを作ります。ここで `EventHandler(Of LowStockEventArgs)` が登場します。

.net
‘ 2. イベントを発行するクラス
Public Class InventoryManager

‘ 型安全なイベントの定義
‘ 標準の EventArgs ではなく、先ほど作った LowStockEventArgs を指定する
Public Event LowStockAlert As EventHandler(Of LowStockEventArgs)

‘ 在庫をチェックし、少なくなっていればイベントを発行するメソッド
public Sub CheckStock(productName As String, stock As Integer)
Const Threshold As Integer = 5 ‘ 警告しきい値

If stock <= Threshold Then ' イベントを発行する(リスナーに通知する) ' 安全に発行するため、イベントがNothing(購読者ゼロ)でないか確認する RaiseEvent LowStockAlert(Me, New LowStockEventArgs(productName, stock)) End If End Sub End Class

ステップ3:イベントを購読して受け取る側を作る

最後に、このマネージャーを利用し、警告イベントを受け取って画面にメッセージを出す側のコードです。

.net
‘ 3. イベントを購読するメイン処理やフォーム
Module Program
Sub Main()
‘ 発行元のインスタンス化
Dim manager As New InventoryManager

‘ ★イベントの購読(AddHandler または Handlesキーワードを使用)
‘ マネージャーが「LowStockAlert」と言ったら、このSubプロシージャ(OnLowStockReceived)を動かす、という契約を結びます。
AddHandler manager.LowStockAlert, AddressOf OnLowStockReceived

‘ — テスト実行 —
Console.WriteLine(“— 在庫チェック開始 —“)

manager.CheckStock(“ノートPC”, 12) ‘ 問題なし(イベントは起きない)
manager.CheckStock(“ワイヤレスマウス”, 3) ‘ ➡ ここで警告イベントが発生するはず!

Console.WriteLine(“— 在庫チェック終了 —“)
Console.ReadLine()
End Sub

‘ イベントハンドラー(イベントが発生したときに呼ばれるメソッド)
‘ シグネチャ(引数の形)は EventHandler(Of T) の規約に合わせます。
Private Sub OnLowStockReceived(sender As Object, e As LowStockEventArgs)
‘ 型安全なので、e.ProductName や e.CurrentStock に迷わずアクセスできる!
Console.WriteLine($”【警告】商品「{e.ProductName}」の在庫が残り {e.CurrentStock} 個です!発注を検討してください。”)
End Sub
End Module

4. 陥りやすい罠とエラー回避の知見

実務でこのパターンを使う際、中級者がハマりがちなポイントをいくつかシェアしておきます。

① メモリリーク(イベントの解除忘れ)に注意せよ

特にWindowsフォームやWPFなどのデスクトップアプリで、短いスパンで生成・破棄される画面(UserControlなど)から、長寿命のシングルトンなクラスに対して `AddHandler` を行った場合、イベントの解除を忘れるとガベージコレクションが働かず、メモリリーク(メモリ食い潰しエラー)を引き起こします。

不要になったら必ず `RemoveHandler` を呼ぶか、フォームの `Disposed` イベント等で片付けをする癖をつけましょう。

.net
‘ 不要になったら購読を解除する
RemoveHandler manager.LowStockAlert, AddressOf OnLowStockReceived

② スレッド間の競合(クロススレッド操作例外)

バックグラウンドスレッド(`Task` や `BackgroundWorker`)の中でイベントを発行し、そのイベントを受け取った側がUI(WindowsフォームのTextBoxなど)を直接書き換えようとすると、「クロススレッド操作が有効です…」というお馴染みのクラッシュ例外が発生します。

イベントを発行する側、あるいは受け取る側で、必要に応じて `Invoke`(UIスレッドへのマーシャリング)を挟む配慮が必要です。

まとめ:ここをクリアすればVB.NETの基本はバッチリ!

今回は `EventHandler(Of T)` を使った型安全なカスタムイベントの設計について解説しました。

  • 標準の `EventArgs` だけでなく、業務に必要なデータを詰め込んだカスタムクラスを作る
  • `EventHandler(Of T)` を使って、コンパイル時に型の安全性を担保する
  • `AddHandler` と `RaiseEvent` で、疎結合な美しいアーキテクチャを作る

マクロの記録や、ただ画面にコードをベタ書きするフェーズから抜け出し、こうした「クラス設計の作法」を取り入れると、VB.NETでのプログラミングが何倍も楽しく、そして堅牢になります。

ここをクリアしたあなたなら、もう立派な中級エンジニアです。ぜひ実際の業務システムやツール開発に取り入れてみてくださいね。それでは、次のステップへ向かって一緒に頑張りましょう!

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