【実務・中級編】上級プロフェッショナル向け:VB.NETでのカスタム属性(Custom Attributes)の自作とリフレクションによるメタデータ駆動型プログラミング – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

メタデータでコードを支配せよ:VB.NETにおけるカスタム属性とリフレクションの極致

「ハードコーディングされたバリデーションロジック」で、コードベースを汚染するのはもうやめよう。

業務自動化ツールの開発において、最も避けるべきは「仕様変更のたびにif文を書き換える」という地獄の保守作業だ。真の上級者は、ロジックをクラスの外側――すなわちメタデータ――に逃がす。

今回は、VB.NETの「カスタム属性(Custom Attributes)」を駆使し、リフレクションを通じて動的に振る舞いを制御する、プロフェッショナルな設計手法を伝授する。

1. なぜ「属性」で設計するのか

多くの開発者は、プロパティの値をチェックするために `If property.Value > 100 Then …` といったコードをあちこちに散らばらせる。だが、これが100箇所あったらどうなるか? 修正漏れによるバグは必至だ。

属性(Attribute)を使えば、対象のプロパティに「これは100以下であるべき」という宣言を付与するだけで済む。ロジックの本体は、リフレクションを用いて実行時に一度だけ記述すればよい。これが「DRY原則(Don’t Repeat Yourself)」の極致だ。

2. カスタム属性の実装:設計の肝

まずは、バリデーションのためのメタデータを定義する。ポイントは `AttributeUsage` 属性で、この属性がどこに適用できるかを厳密に制限することだ。

Imports System

‘ 属性の適用範囲をプロパティのみに制限し、継承を許可する

Public Class RangeValidationAttribute
Inherits Attribute

Public Property MinValue As Integer
Public Property MaxValue As Integer

Public Sub New(min As Integer, max As Integer)
Me.MinValue = min
Me.MaxValue = max
End Sub
End Class

3. リフレクションによるメタデータ駆動型エンジン

次に、この属性を読み取り、検証を行うエンジンを作成する。ここで注意すべきはパフォーマンスだ。リフレクションは高コストな処理であるため、プロダクションコードでは必ず「キャッシュ」を考慮しなければならない。

Imports System.Reflection

Public Class Validator
‘ リフレクションのパフォーマンス低下を防ぐための簡易キャッシュ
Private Shared _cache As New Collections.Generic.Dictionary(Of Type, PropertyInfo())

Public Shared Function Validate(obj As Object) As Boolean
Dim t As Type = obj.GetType()
Dim props As PropertyInfo()

‘ キャッシュがあれば再利用、なければ取得
If Not _cache.ContainsKey(t) Then
_cache(t) = t.GetProperties()
End If
props = _cache(t)

For Each prop In props
‘ 属性を取得
Dim attr = prop.GetCustomAttribute(Of RangeValidationAttribute)()
If attr IsNot Nothing Then
Dim val = CInt(prop.GetValue(obj))
‘ 検証ロジック
If val < attr.MinValue OrElse val > attr.MaxValue Then
Throw New Exception($”{prop.Name} が範囲外です: {val}”)
End If
End If
Next
Return True
End Function
End Class

4. 実装:スマートなデータモデル

これを使う側のコードは、驚くほどクリーンになる。

Public Class UserData

Public Property Age As Integer


Public Property Salary As Integer
End Class

‘ 実行例
Dim user As New UserData With {.Age = 25, .Salary = 500000}
Try
Validator.Validate(user)
Console.WriteLine(“検証完了”)
Catch ex As Exception
Console.WriteLine($”エラー: {ex.Message}”)
End Try

5. 現場で生き残るための「鉄則」

この手法を実務で採用する際、以下の3点だけは肝に銘じておいてほしい。

1. リフレクションのキャッシュは必須: 上記例のように `Dictionary` を使用し、型情報を保持せよ。ループ内で毎回 `GetProperties()` を呼ぶようなコードは、データ件数が増えた瞬間にツールを崩壊させる。
2. 型安全性の確保: `GetValue` で取得した値が、期待する型と一致するかどうかは常に気にする必要がある。必要であれば `TryCast` を活用し、クラッシュしない設計を目指せ。
3. データベース連携時の注意: このバリデーションはあくまで「アプリケーション層」のガードだ。DBの制約(Not Nullや文字数制限)と、属性によるバリデーションの整合性をドキュメント化しておくことが、チーム開発における「無言の信頼」を築く。

最後に

メタデータ駆動型プログラミングは、コードの「記述量」を減らすことではなく、コードの「依存関係」を整理することにある。

VB.NETは古臭い言語だという揶揄があるが、リフレクションと属性を理解したエンジニアの手にかかれば、極めて強力な自動化エンジンへと化ける。さあ、今すぐ退屈なif文の羅列を捨て、このアーキテクチャで「変更に強いシステム」を構築してほしい。

健闘を祈る。

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