Bagaimana cara mendapatkan daftar properti dengan atribut yang diberikan?

210

Saya memiliki tipe,, tdan saya ingin mendapatkan daftar properti publik yang memiliki atribut MyAttribute. Atribut ditandai dengan AllowMultiple = false, seperti ini:

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

Saat ini yang saya miliki adalah ini, tetapi saya berpikir ada cara yang lebih baik:

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

Bagaimana saya bisa meningkatkan ini? Saya minta maaf jika ini adalah duplikat, ada satu ton utas refleksi di luar sana ... sepertinya itu topik yang cukup panas.

wsanville
sumber
Nggak. Anda memerlukan PropertyInfo sebelum Anda dapat mengetahui apakah properti tersebut memiliki atribut.
Hans Passant

Jawaban:

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

Ini menghindari keharusan mematerialisasikan instance atribut apa pun (yaitu lebih murah dari GetCustomAttribute[s]().

Marc Gravell
sumber
1
Saran yang bagus Namun saya akan membutuhkan atribut atribut, tetapi saya menyukainya.
wsanville
1
Saya hanya mencari cara untuk memeriksa keberadaan atribut tanpa efek samping yang disebut properti. Terima kasih Marc, berhasil!
Örjan Jämte
1
@ ÖrjanJämte properti gettidak dipanggil bahkan saat menggunakan GetCustomAttributes; Namun, atribut tersebut dipakai , yang tidak gratis. Jika Anda tidak perlu memeriksa nilai atribut tertentu, IsDefinedlebih murah. Dan pada 4.5, ada cara untuk memeriksa data instantiasi tanpa benar - benar membuat instances atribut apa pun (walaupun ini dimaksudkan hanya untuk skenario yang sangat spesifik)
Marc Gravell
2
@bjhuffine msdn.microsoft.com/en-us/library/…
Marc Gravell
2
untuk dotnet core: var props = t.GetProperties (). Di mana (e => e.IsDefined (typeof (MyAttribute))));
Rtype
45

Solusi yang saya gunakan paling banyak didasarkan pada jawaban Tomas Petricek. Saya biasanya ingin melakukan sesuatu dengan baik atribut dan properti.

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};
wsanville
sumber
+1 - "Saya biasanya ingin melakukan sesuatu dengan atribut dan properti" adalah apa yang saya cari - terima kasih banyak telah mengirimkan jawaban Anda!
Yawar Murtaza
34

Sejauh yang saya tahu, tidak ada cara yang lebih baik dalam hal bekerja dengan perpustakaan Reflection dengan cara yang lebih cerdas. Namun, Anda bisa menggunakan LINQ untuk membuat kode sedikit lebih baik:

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'

Saya percaya ini membantu Anda menyusun kode dengan cara yang lebih mudah dibaca.

Tomas Petricek
sumber
13

Selalu ada LINQ:

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

Jika Anda berurusan secara teratur dengan Atribut dalam Refleksi, sangat, sangat praktis untuk mendefinisikan beberapa metode ekstensi. Anda akan melihat bahwa dalam banyak proyek di luar sana. Yang ini adalah yang sering saya miliki:

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

yang dapat Anda gunakan suka typeof(Foo).HasAttribute<BarAttribute>();

Proyek-proyek lain (misalnya StructureMap) memiliki kelas ReflectionHelper lengkap yang menggunakan pohon Expression untuk memiliki sintaksis yang baik untuk identitas misalnya PropertyInfos. Penggunaan kemudian terlihat seperti itu:

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

Selain jawaban sebelumnya: lebih baik menggunakan metode Any()daripada memeriksa panjang koleksi:

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

Contoh di dotnetfiddle: https://dotnetfiddle.net/96mKep

penerima bayaran
sumber
@ cogumel0 Pertama-tama, pasti .Any()tidak memeriksa panjangnya. Tetapi jawaban saya bukan tentang properti yang ditemukan dengan tepat satu atribut. Kedua, saya tidak yakin Anda membaca kode dengan benar - .Anymetode memanggil hasil dari GetCustomAttrubutesmetode tersebut. Jadi tipe dari propertiesWithMyAttributekoleksi properti. Lihatlah contohnya di dotnetfiddle (saya menambahkan tautan ke jawabannya).
penerima bayaran
1
Anda dapat mengganti. Di mana dengan .Any, karena .Any juga memungkinkan lambdas.
PRMan