【入門編】VB.NETで実現するカスタム属性(Attribute)を用いた入力値バリデーションフレームワークの自社開発 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは!
VBAでの「マクロの記録」や、決まりきったボタンクリックのイベント処理から一歩抜け出して、「もっとスマートで保守性の高いWindows Formsアプリを作りたい!」と悩んでいませんか?

今回は、プロの現場でもよく使われる「カスタム属性(Attribute)」という武器を使って、入力値のバリデーション(エラーチェック)を劇的に自動化するフレームワークの作り方を解説します。

「属性って何?難しそう……」と思うかもしれませんが、大丈夫です。ここをクリアすれば、あなたのVB.NETのスキルは間違いなくワンランク上のステージに到達します。優しく丁寧に案内していきますので、一緒に進めていきましょう!

—

1. なぜ「カスタム属性」を使うのか?(従来の課題)

Windows Formsでテキストボックスに入力された値が「空っぽになっていないか」「数字だけか」をチェックするとき、皆さんはどう書いているでしょうか?

多くの人は、保存ボタンが押されたときに、こんなコードを書いてしまいます。

.NET
‘ 昔ながらの泥臭いチェック処理
If String.IsNullOrWhiteSpace(txtUserName.Text) Then
MessageBox.Show(“ユーザー名を入力してください。”)
txtUserName.Focus()
Exit Sub
End If

If Not IsNumeric(txtAge.Text) Then
MessageBox.Show(“年齢には数値を入力してください。”)
txtAge.Focus()
Exit Sub
End If

画面の項目が3つくらいならこれでもいいですが、項目が20個、30個と増えたらどうでしょう? `If`文の嵐になり、仕様変更があったときに修正漏れが続出する「メンテナンス地獄」が待っています。

ここで登場するのがカスタム属性(Attribute)です。
コントロールの定義(プロパティ)に、「これは必須ですよ」「ここは数値だけですよ」と「名札(アノテーション)」を貼るだけで、検証エンジンが勝手にチェックしてくれる仕組みを作ります。

—

2. フレームワークの全体像

私たちが目指す世界はシンプルです。フォームに配置したコントロールに対して、以下のように属性を付与するだけで準備完了となります。

.NET
‘ 例:名前は必須、年齢は数値のみ、かつ空欄不可

Public Property UserName As String



Public Property UserAge As String

この仕組みを作るために、以下の3つのステップを踏みます。

1. カスタム属性クラスの作成(ルールの定義)
2. 検証エンジン(Validator)の作成(チェック処理の本体)
3. フォームへの組み込み(実行)

—

3. 実装コード:一歩ずつ作ってみよう

それでは、Visual Studioを開いて、実際にコードを書いていきましょう。

Step 1: カスタム属性のベースと「必須チェック」を作る

まずは、属性の基本となるクラスを作ります。VB.NETでは、`Attribute`クラスを継承することで、独自の属性を作ることができます。

.NET
Imports System

‘ 1. すべての検証属性のベースとなるクラス

Public MustInherit Class ValidationAttribute
Inherits Attribute

‘ エラーメッセージを保持するプロパティ
Public Property ErrorMessage As String

Protected Sub New(errorMessage As String)
Me.ErrorMessage = errorMessage
End Sub

‘ 実際の検証処理(派生クラスでオーバーライドする)
Public MustOverride Function IsValid(value As Object) As Boolean
End Class

‘ 2. 「必須入力」を表すカスタム属性

Public NotInheritable Class RequiredAttribute
Inherits ValidationAttribute

Public Sub New(errorMessage As String)
MyBase.New(errorMessage)
End Sub

Public Overrides Function IsValid(value As Object) As Boolean
Dim strValue As String = TryCast(value, String)
‘ 文字列がNothing、または空白文字だけの場合はエラー
Return Not String.IsNullOrWhiteSpace(strValue)
End Function
End Class

Step 2: 「数値チェック」を追加する

ついでにもう一つ、「数値かどうか」をチェックする属性も追加しましょう。

.NET
‘ 3. 「数値のみ」を表すカスタム属性

Public NotInheritable Class NumericOnlyAttribute
Inherits ValidationAttribute

Public Sub New(errorMessage As String)
MyBase.New(errorMessage)
End Sub

Public Overrides Function IsValid(value As Object) As Boolean
Dim strValue As String = TryCast(value, String)
If String.IsNullOrEmpty(strValue) then
Return True ‘ 空欄のチェックはRequiredAttributeの仕事なので、ここではスルー
End If

Dim number As Double
Return Double.TryParse(strValue, number)
End Function
End Class

Step 3: 魔法の検証エンジンを作る(リフレクションの活用)

ここが今回のハイライトです。.NETのリフレクション(実行時にプログラム自身の構造を調べる機能)を使って、オブジェクトに付与された属性を自動で読み取り、検証するエンジンを作ります。

.NET
Imports System.Reflection

Public Class ModelValidator

‘ オブジェクトを受け取り、付与された属性を元に一括検証する
Public Shared Function Validate(model As Object, ByRef errorMessage As String) As Boolean
Dim modelType As Model.GetType()

‘ モデルが持つすべてのプロパティをループで走査
For Each prop As PropertyInfo In modelType.GetProperties()

‘ プロパティに付与されている「ValidationAttribute」をすべて取得
Dim attributes = prop.GetCustomAttributes(GetType(ValidationAttribute), True)

For Each attr As ValidationAttribute In attributes
‘ プロパティから現在の値を取得
Dim value = prop.GetValue(model)

‘ 検証を実行
If Not attr.IsValid(value) Then
errorMessage = attr.ErrorMessage
Return False ‘ エラーが見つかったら即座に中断
End If
Next
Next

errorMessage = String.Empty
Return True
End Function

End Class

—

4. 実際のWindows Forms画面で使ってみる

さて、いよいよ作った仕組みを画面(Form)に組み込みます。
今回は、ViewModel(データ構造クラス)とWindows Formsのコントロールをバインドする形を想定してみましょう。

.NET
‘ 入力データを保持するクラス(ここに属性を貼る!)
Public Class UserInputModel


Public Property Name As String



Public Property Age As String

End Class

そして、フォーム側の保存ボタンのイベントは、たったこれだけになります!

.NET
Public Class MainForm

Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click

‘ 1. 画面の入力値をモデルに詰める
Dim model As New UserInputModel() With {
.Name = txtName.Text.Trim(),
.Age = txtAge.Text.Trim()
}

‘ 2. エンジンに検証を丸投げする!
Dim errMsg As String = “”
If Not ModelValidator.Validate(model, errMsg) Then
‘ エラーがあればメッセージを出して終了
MessageBox.Show(errMsg, “入力エラー”, MessageBoxButtons.OK, MessageBoxIcon.Warning)
Return
End If

‘ 3. 検証クリア!保存処理へ進む
MessageBox.Show(“入力チェックをクリアしました!保存処理を実行します。”, “成功”, MessageBoxButtons.OK, MessageBoxIcon.Information)

End Sub

End Class

—

5. 陥りやすいエラーと知っておくべきポイント

ここで、実務で開発する際につまづきやすいポイントをいくつか先回りして解説しておきます。

  • `TryCast` と `DirectCast` の違い

今回のコードでは `TryCast(value, String)` を使っています。これは、キャストに失敗しても例外(クラッシュ)を起きずに `Nothing` を返してくれる安全なキャストです。UIからの入力値は予期せぬ型が入る可能性があるため、安全な `TryCast` を使いましょう。

  • 属性を貼るターゲットのミス

`AttributeUsage(AttributeTargets.Property)` と指定しているため、この属性はプロパティに対してのみ付与できます。クラスやメソッドに間違えて貼るとコンパイルエラーになるため、意図通りに設計制限をかけることができます。

—

おわりに:ここをクリアすれば、VB.NETの基本はバッチリ!

いかがでしたでしょうか?
今回はカスタム属性とリフレクションという、少し高度な.NETの機能を組み合わせたバリデーションフレームワークをご紹介しました。

「画面のコントロールを一つずつ `If` 文でチェックする」という泥臭いコードから卒業し、「ルールをデータ(属性)として宣言する」というモダンな設計手法を手に入れることで、あなたの書くコードは一気にプロのクオリティへと進化します。

ここをマスターできれば、VB.NETやC#におけるオブジェクト指向の本質、そしてフレームワーク設計の面白さがグッと見えてくるはずです。ぜひ、ご自身のプロジェクトでも試してみてくださいね。

それでは、快適なVB.NETライフを!

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