特定の属性を持つプロパティのリストを取得するにはどうすればよいですか?


210

タイプtがあり、属性を持つパブリックプロパティのリストを取得したいと考えていますMyAttribute。この属性はAllowMultiple = false、次のようにでマークされています。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]

現在私が持っているのはこれですが、もっと良い方法があると思っています:

foreach (PropertyInfo prop in t.GetProperties())
{
    object[] attributes = prop.GetCustomAttributes(typeof(MyAttribute), true);
    if (attributes.Length == 1)
    {
         //Property with my custom attribute
    }
}

どうすればこれを改善できますか?申し訳ありませんが、これが重複している場合、そこには大量のリフレクションスレッドがあります...それは非常にホットなトピックのようです。


いいえ。プロパティに属性があるかどうかを確認する前に、PropertyInfoが必要です。
ハンスパッサント2010

回答:


391
var props = t.GetProperties().Where(
                prop => Attribute.IsDefined(prop, typeof(MyAttribute)));

これにより、属性インスタンスを具体化する必要がなくなります(つまり、よりも安価です)GetCustomAttribute[s]()


1
良い提案。ただし、属性インスタンスは必要ですが、私はそれが好きです。
wsanville

1
プロパティgetが呼び出されるという副作用なしに属性の存在を確認する方法を探していました。マルクさん、ありがとうございます。
ÖrjanJämte

1
@ÖrjanJämte getを使用しても、プロパティは呼び出されませんGetCustomAttributes。ただし、属性はインスタンス化されているため、無料ではありません。属性の特定の値を確認する必要がない場合IsDefinedは、より安価です。4.5では、属性インスタンス実際に作成せずにインスタンス化データをチェックする方法があります(これは非常に特定のシナリオのみを対象としています)
Marc Gravell


2
dotnetコアの場合:var props = t.GetProperties()。Where(e => e.IsDefined(typeof(MyAttribute)));
Rtype 2017

45

私が最もよく使用するソリューションは、Tomas Petricekの回答に基づいています。私は通常、属性とプロパティの両方で何かをしたいです。

var props = from p in this.GetType().GetProperties()
            let attr = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attr.Length == 1
            select new { Property = p, Attribute = attr.First() as MyAttribute};

+1-「私は通常、属性とプロパティの両方で何かをしたいです」が私が探していたものです-あなたの答えを投稿してくれてありがとう!
Yawar Murtaza 2017年

34

私の知る限り、Reflectionライブラリをよりスマートに操作するためのより良い方法はありません。ただし、LINQを使用してコードを少し良くすることができます。

var props = from p in t.GetProperties()
            let attrs = p.GetCustomAttributes(typeof(MyAttribute), true)
            where attrs.Length != 0 select p;

// Do something with the properties in 'props'

これは、コードをより読みやすい方法で構造化するのに役立つと思います。


13

常にLINQがあります。

t.GetProperties().Where(
    p=>p.GetCustomAttributes(typeof(MyAttribute), true).Length != 0)

6

Reflectionの属性を定期的に扱う場合、いくつかの拡張メソッドを定義することは非常に実用的です。あなたはそこにある多くのプロジェクトでそれを見るでしょう。これは私がよく持っているものです:

public static bool HasAttribute<T>(this ICustomAttributeProvider provider) where T : Attribute
{
  var atts = provider.GetCustomAttributes(typeof(T), true);
  return atts.Length > 0;
}

あなたはこのように使うことができます typeof(Foo).HasAttribute<BarAttribute>();

他のプロジェクト(StructureMapなど)には、式ツリーを使用してPropertyInfosなどの識別に細かい構文を使用する本格的なReflectionHelperクラスがあります。使用方法は次のようになります。

ReflectionHelper.GetProperty<Foo>(x => x.MyProperty).HasAttribute<BarAttribute>()

2

以前の回答に加えてAny()、コレクションの長さをチェックするのではなく、メソッドを使用することをお勧めします。

propertiesWithMyAttribute = type.GetProperties()
  .Where(x => x.GetCustomAttributes(typeof(MyAttribute), true).Any());

dotnetfiddleの例:https ://dotnetfiddle.net/96mKep


@ cogumel0まず第一に、確か.Any()に長さをチェックしません。しかし、私の答えは、ただ1つの属性を持つプロパティを見つけることではありませんでした。次に、コードを正しく読んだかどうかはわかりません。メソッドの.Any結果に対してメソッドが呼び出されGetCustomAttrubutesます。したがって、タイプはpropertiesWithMyAttributeプロパティのコレクションになります。dotnetfiddleの例を確認してください(回答へのリンクを追加します)。
18

1
.Anyはラムダも許可するため、.Whereを.Anyに置き換えることができます。
PRMan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.