วิธีรับรายการคุณสมบัติพร้อมแอตทริบิวต์ที่กำหนด?


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
    }
}

ฉันจะปรับปรุงสิ่งนี้ได้อย่างไร คำขอโทษของฉันหากนี่คือสิ่งที่ซ้ำกันมีเธรดการสะท้อนจำนวนมากออกมาที่นั่น ... ดูเหมือนว่าจะเป็นประเด็นร้อนแรง


Nope คุณต้องมี PropertyInfo ก่อนจึงจะสามารถค้นหาได้ว่าคุณสมบัตินั้นมีแอตทริบิวต์หรือไม่
Hans Passant

คำตอบ:


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

หลีกเลี่ยงนี้ต้องเป็นตัวเป็นตนกรณีแอตทริบิวต์ใด ๆ GetCustomAttribute[s]()(คือมันมีราคาถูกกว่า


1
คำแนะนำที่ดี อย่างไรก็ตามฉันจะต้องการอินสแตนซ์ของแอตทริบิวต์ แต่ฉันชอบ
wsanville

1
ฉันแค่มองหาวิธีที่จะตรวจสอบการมีอยู่ของคุณลักษณะโดยไม่มีผลข้างเคียงที่คุณสมบัติได้รับเรียก ขอบคุณ Marc มันใช้งานได้!
ÖrjanJämte

1
@ ÖrjanJämteทรัพย์สินที่getไม่ได้เรียกว่าแม้ในขณะที่การใช้GetCustomAttributes; อย่างไรก็ตามคุณลักษณะนั้นเป็นอินสแตนซ์ซึ่งไม่ฟรี หากคุณไม่จำเป็นต้องตรวจสอบค่าเฉพาะของแอตทริบิวต์นั้นIsDefinedจะถูกกว่า และใน 4.5 มีวิธีตรวจสอบข้อมูลอินสแตนซ์โดยไม่ต้องสร้างอินสแตนซ์ของแอตทริบิวต์ใด ๆ (แม้ว่าจะมีไว้สำหรับสถานการณ์ที่เฉพาะเจาะจงเท่านั้น)
Marc Gravell


2
สำหรับ dotnet core: var props = t.GetProperties () โดยที่ (e => e.IsDefined (typeof (MyAttribute)));
Rtype

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

34

เท่าที่ฉันรู้ไม่มีวิธีใดที่ดีไปกว่าในการทำงานกับห้องสมุดรีเฟลคชั่นอย่างชาญฉลาด อย่างไรก็ตามคุณสามารถใช้ 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'

ฉันเชื่อว่าสิ่งนี้จะช่วยให้คุณสามารถจัดโครงสร้างโค้ดในแบบที่อ่านง่ายขึ้น



6

หากคุณจัดการกับ Attributes in 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) มีคลาส ReflectionHelper เต็มรูปแบบที่ใช้ต้นไม้ Expression เพื่อมีไวยากรณ์ที่ดีในการระบุตัวตนเช่น PropertyInfos การใช้งานดูเหมือนว่า:

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()ว่าไม่ได้ตรวจสอบความยาว แต่คำตอบของฉันไม่เกี่ยวกับคุณสมบัติที่พบซึ่งมีคุณสมบัติเดียว ประการที่สองฉันไม่แน่ใจว่าคุณอ่านรหัสอย่างถูกต้อง - .Anyวิธีการที่เรียกว่าผลลัพธ์ของGetCustomAttrubutesวิธีการ ดังนั้นชนิดของการpropertiesWithMyAttributeจะเป็นชุดของคุณสมบัติ ลองดูตัวอย่างที่ dotnetfiddle (ฉันเพิ่มลิงค์ไปยังคำตอบ)
feeeper

1
คุณสามารถแทนที่ได้. ด้วย. ใด ๆ ตั้งแต่. ใด ๆ ยังช่วยให้ lambdas
PRMan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.