C#の「属性(Attribute)」機能を使用すると、クラスやプロパティに追加のメタデータ(最大文字数、必須項目、DBのカラム名など)を付与できます。
プログラムの実行時に、特定のプロパティにこれらの属性が付いているかどうかをチェックするには、リフレクションの IsDefined メソッドを使用します。これは、バリデーションライブラリやO/Rマッパーを自作する際によく利用される技術です。
目次
属性の有無を確認する実装
以下のサンプルコードでは、Product クラスの Name プロパティに対し、MaxLengthAttribute(最大長制約)が付与されているかどうかを判定しています。
サンプルコード
using System;
using System.ComponentModel.DataAnnotations; // 属性を利用するための名前空間
using System.Reflection;
public class Program
{
public static void Main()
{
// 1. 対象の型情報を取得
Type type = typeof(Product);
// 2. 調査したいプロパティ情報を取得
PropertyInfo prop = type.GetProperty("Name");
if (prop != null)
{
// 3. 指定した属性が付与されているか判定
// 第1引数: 属性の型
// 第2引数:継承元も探索するか (true/false)
bool isDefined = prop.IsDefined(typeof(MaxLengthAttribute), inherit: true);
if (isDefined)
{
Console.WriteLine($"プロパティ '{prop.Name}' には MaxLengthAttribute が適用されています。");
}
else
{
Console.WriteLine($"プロパティ '{prop.Name}' には MaxLengthAttribute は適用されていません。");
}
// (参考) 属性が付与されていないプロパティのチェック
PropertyInfo priceProp = type.GetProperty("UnitPrice");
if (!priceProp.IsDefined(typeof(MaxLengthAttribute), inherit: true))
{
Console.WriteLine($"プロパティ '{priceProp.Name}' には MaxLengthAttribute は適用されていません。");
}
}
}
}
// サンプル用クラス
public class Product
{
// MaxLength属性を付与
[MaxLength(100)]
public string Name { get; set; }
// 属性なし
public int UnitPrice { get; set; }
}
実行結果
プロパティ 'Name' には MaxLengthAttribute が適用されています。
プロパティ 'UnitPrice' には MaxLengthAttribute は適用されていません。
解説と技術的なポイント
1. IsDefined メソッド
MemberInfo(PropertyInfo の親クラス)に定義されているメソッドで、指定された属性型がそのメンバーに適用されているかを true / false で返します。
- 構文:
bool IsDefined(Type attributeType, bool inherit) - inherit引数:
trueを指定すると、親クラスで定義された属性も含めて検索します(継承可能な属性の場合)。通常はtrueを指定するのが一般的です。
2. GetCustomAttribute との使い分け
属性の有無だけでなく、属性に設定されている値(上記の例なら 100)も取得したい場合は、IsDefined ではなく GetCustomAttribute メソッドを使用します。
- IsDefined: 「付いているか」だけを高速にチェックしたい場合に使用。
- GetCustomAttribute: 属性のインスタンスを取得し、プロパティ値などを読み取りたい場合に使用。
3. 前提条件
[MaxLength] などの標準的な属性を使用するには、プロジェクト参照に System.ComponentModel.DataAnnotations アセンブリが含まれている必要があります(近年の.NET環境では標準で利用可能です)。
