PG日誌

各記事はブラウザの横幅を1410px以上にすると2カラムの見出しが表示されます。なるべく横に広げてみてください。

【C#】プロパティにつけた属性を取得する方法

C#でプロパティにつけた属性を取得する方法の紹介です。自作のクラスなどでプロパティに付与したカスタム属性を取得してその値を利用する方法です。

確認環境

  • C# 8.0
  • .NET Core 3.1
  • VisualStudio 2019
  • Windows10

コンソールプログラムで動作を確認

実装コード

取得方法は以下の通りです。すべての処理で共通してインスタンスか型(Type)を指定して、属性を取得したいプロパティの名前を文字列で指定します。

この名前を文字列で指定するのは

public static class AttributeUtility
{
    //
    // T で指定したプロパティを1つだけ取得
    //

    // 型を指定して Public プロパティの属性を取得する
    public static T GetPropertyAttribute<T>(Type type, string name) where T : Attribute
    {
        var prop = type.GetProperty(name);
        if (prop == null)
        {
            Trace.WriteLine($"Property is not found. {name}");
            return default; // 指定したプロパティが見つからない
        }
        var att = prop.GetCustomAttribute<T>();
        if (att == null)
        {
            Trace.WriteLine($"Attribute is not found. {name}");
            return default; // 指定した属性が付与されていない
        }
        return att;
    }

    //
    // プロパティについている属性を全部取得
    //
    
    // インスタンスを指定して Public プロパティの属性を取得します。
    public static T GetPropertyAttribute<T>(object instance, string name) where T : Attribute
    {
        return GetPropertyAttribute<T>(instance.GetType(), name);
    }

    // 型を指定して Public プロパティに付与されているすべてのプロパティを取得する
    public static IEnumerable<Attribute> GetPropertyAttributes(Type type, string name)
    {
        var prop = type.GetProperty(name);
        if (prop == null)
        {
            Trace.WriteLine($"Property is not found. {name}");
            return default;
        }

        return prop.GetCustomAttributes<Attribute>();
    }

    // インスタンスを指定して Public プロパティに付与されているすべてのプロパティを取得する
    public static IEnumerable<Attribute> GetPropertyAttributes(object instance, string name)
    {
        return GetPropertyAttributes(instance.GetType(), name);
    }
}

public なプロパティしか対象としていませんがそれ以外のプロパティから属性を取得したい場合は、以下のように GetProperty() メソッドに BindingFlags を指定するように修正します。

// 以下の通りコードを修正する
var prop = 
    type.GetProperty(name, 
        BindingFlags.InvokeMethod | // ★ここから追加
        BindingFlags.NonPublic | 
        BindingFlags.Instance);

使いかた

例えば以下のような自作のカスタム属性を2つ用意し、それがプロパティに付与されているとします。

// 1つ目の属性
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class IDAttribute : Attribute
{
    public string ID { get; set; }
    
    public IDAttribute(string id)
    {
        this.ID = id;
    }
}

// 2つ目の属性
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class TagAttribute : Attribute
{
    public string Tag { get; set; }

    public TagAttribute(string tag)
    {
        this.Tag = tag;
    }
}

// プロパティに上記2つの属性を付与する
public class Sample
{
    [ID("ididid"), Tag("tagtag")]
    public string Name { get; set; }
}

上記の属性は以下のように取得します。

public static void Main(string[] args)
{
    var s = new Sample() { Name = "000", };

    // ひとつだけ属性を取得する場合
    var attribute = AttributeUtility.GetPropertyAttribute< IDAttribute>(s, nameof(Sample.Name));
    Console.WriteLine(attribute.ID);
    // > ididid

    // 全部取得する場合
    var list = AttributeUtility.GetPropertyAttributes(s, nameof(Sample.Name));
    foreach (var att in list)
    {
        Console.WriteLine(att.GetType().Name);
        // > IDAttribute
        // > TagAttribute
    }
}