特定のプロパティに付与された属性(Attribute)が存在するかを確認するだけでなく、その属性に設定された具体的な値(例:画面表示用のラベル名、エラーメッセージ、設定値など)を読み取りたいケースがあります。
C#のリフレクションと拡張メソッド GetCustomAttribute<T> を使用することで、属性オブジェクトのインスタンスそのものを取得し、そのプロパティ値にアクセスすることが可能です。
属性値の取得実装
以下のサンプルコードでは、Product クラスのプロパティに付与された [Display(Name="...")] 属性から、日本語の表示名を取り出してコンソールに出力する処理を実装しています。
サンプルコード
using System;
using System.ComponentModel.DataAnnotations; // Display属性用
using System.Reflection;
public class Program
{
public static void Main()
{
// 1. 対象の型情報を取得
Type type = typeof(Product);
Console.WriteLine("--- 属性値の取得結果 ---");
// 2. 各プロパティのDisplay属性値を取得して表示
// nameof演算子を使うことで、プロパティ名の変更に強くなります
PrintDisplayName(type, nameof(Product.ProductName));
PrintDisplayName(type, nameof(Product.UnitPrice));
// (参考) 属性が付いていないプロパティの場合
PrintDisplayName(type, nameof(Product.StockCount));
}
/// <summary>
/// 指定されたプロパティのDisplay属性のName値を出力する
/// </summary>
static void PrintDisplayName(Type type, string propertyName)
{
// プロパティ情報を取得
PropertyInfo prop = type.GetProperty(propertyName);
if (prop == null) return;
// 3. 属性インスタンスを取得
// GetCustomAttribute<T>() は、指定した属性が見つかればそのインスタンスを、
// 見つからなければ null を返します。
var attr = prop.GetCustomAttribute<DisplayAttribute>();
if (attr != null)
{
// 属性のプロパティ(Name)にアクセス
Console.WriteLine($"プロパティ: {propertyName,-12} | 表示名: {attr.Name}");
}
else
{
Console.WriteLine($"プロパティ: {propertyName,-12} | 属性なし");
}
}
}
// データクラス
public class Product
{
// 画面表示用の名前を属性で定義
[Display(Name = "商品名")]
public string ProductName { get; set; }
[Display(Name = "商品単価")]
public int UnitPrice { get; set; }
// 属性を付けていないプロパティ
public int StockCount { get; set; }
}
実行結果
--- 属性値の取得結果 ---
プロパティ: ProductName | 表示名: 商品名
プロパティ: UnitPrice | 表示名: 商品単価
プロパティ: StockCount | 属性なし
解説と技術的なポイント
1. GetCustomAttribute<T> メソッド
このメソッドは System.Reflection.CustomAttributeExtensions クラスに含まれる拡張メソッドです。 ジェネリック型引数 T に取得したい属性の型(今回は DisplayAttribute)を指定して呼び出します。 戻り値として属性クラスのインスタンスが返ってくるため、通常のクラスと同じようにドット演算子でプロパティ(attr.Name など)にアクセスできます。
2. nameof 演算子の活用
プロパティ名を文字列リテラル "ProductName" で直接書くことも可能ですが、nameof(Product.ProductName) を使用することで、リファクタリング(名前変更)時の追従漏れを防ぎ、コンパイル時にスペルミスを検出できるようになります。
3. DisplayAttribute について
System.ComponentModel.DataAnnotations 名前空間にある標準的な属性です。 ASP.NET Core MVC や Entity Framework などのフレームワークでは、この属性値を自動的に読み取って、入力フォームのラベルやバリデーションメッセージとして利用する仕組みが組み込まれています。今回のコードは、その「読み取り処理」を自前で実装した形になります。
