クラス定義そのものに付与されたメタデータ(作成者情報、バージョン、非推奨マーク、DBテーブル名など)をプログラム実行時に取得するには、Type クラスの GetCustomAttributes メソッドを使用します。
これにより、特定の属性が付与されたクラスだけを検索してロードしたり、属性に記述された設定値に基づいて振る舞いを変えたりすることが可能になります。
クラス属性の取得実装
以下のサンプルコードでは、クラスの開発者情報を記録するためのカスタム属性 DeveloperInfoAttribute を定義し、それを付与したクラスから情報を読み取る処理を実装しています。また、標準の ObsoleteAttribute(非推奨)も併せて取得します。
サンプルコード
using System;
using System.Reflection;
public class Program
{
public static void Main()
{
// 1. 対象の型情報を取得
Type type = typeof(OldDataProcessor);
Console.WriteLine($"クラス '{type.Name}' の属性一覧:\n");
// 2. クラスに付与されているすべてのカスタム属性を取得
// 引数 inherit: true にすると、親クラスの属性も検索します
object[] attributes = type.GetCustomAttributes(inherit: false);
foreach (var attr in attributes)
{
// 属性の種類に応じた処理
if (attr is DeveloperInfoAttribute devAttr)
{
Console.WriteLine($"[開発者情報] 名前: {devAttr.DeveloperName}, 日付: {devAttr.Date}");
}
else if (attr is ObsoleteAttribute obsAttr)
{
Console.WriteLine($"[非推奨警告] メッセージ: {obsAttr.Message}");
}
else
{
// その他の属性
Console.WriteLine($"[その他] {attr.GetType().Name}");
}
}
}
}
// ---------------------------------------------------------
// カスタム属性の定義
// AttributeUsageで、この属性がクラスに対してのみ有効であることを指定
// ---------------------------------------------------------
[AttributeUsage(AttributeTargets.Class)]
public class DeveloperInfoAttribute : Attribute
{
public string DeveloperName { get; }
public string Date { get; }
public DeveloperInfoAttribute(string developerName, string date)
{
DeveloperName = developerName;
Date = date;
}
}
// ---------------------------------------------------------
// 属性を付与されたクラス
// ---------------------------------------------------------
[DeveloperInfo("山田 太郎", "2023-12-01")]
[Obsolete("このクラスは廃止予定です。NewDataProcessorを使用してください。")]
[Serializable] // 標準的な属性も付与してみる
public class OldDataProcessor
{
public void Process()
{
Console.WriteLine("処理実行...");
}
}
実行結果
クラス 'OldDataProcessor' の属性一覧:
[開発者情報] 名前: 山田 太郎, 日付: 2023-12-01
[非推奨警告] メッセージ: このクラスは廃止予定です。NewDataProcessorを使用してください。
[その他] SerializableAttribute
解説と技術的なポイント
1. GetCustomAttributes メソッド
Type クラス(MemberInfo クラスを継承)のメソッドで、その型に適用されているすべての属性インスタンスを object[] 配列として返します。 特定の属性のみを取得したい場合は、ジェネリック版の GetCustomAttribute<T>()(単一取得)や GetCustomAttributes<T>()(複数取得)を使用するのが便利です。
2. AttributeUsage 属性
自作の属性クラス(ここでは DeveloperInfoAttribute)を作成する際、その属性が「どこに付与できるか(クラス、メソッド、プロパティなど)」を制御するために [AttributeUsage] を使用します。
AttributeTargets.Class: クラスへの付与を許可。AllowMultiple: 同じ属性を複数回付与できるかを指定。
3. 実用例
この技術は、以下のような場面で広く利用されています。
- プラグインシステム: 特定の属性(
[Plugin("Name")]など)が付いたクラスをDLLから探し出してロードする。 - ユニットテスト:
[TestClass]や[TestFixture]が付いたクラスをテストランナーが認識する。 - O/Rマッパー: クラスとデータベースのテーブルを対応付けるために
[Table("TableName")]のような属性を読み取る。
