Làm thế nào để có được một danh sách các thuộc tính với một thuộc tính nhất định?


210

Tôi có một loại, tvà tôi muốn có một danh sách các thuộc tính công cộng có thuộc tính MyAttribute. Thuộc tính được đánh dấu bằng AllowMultiple = false, như thế này:

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

Hiện tại những gì tôi có là cái này, nhưng tôi nghĩ có một cách tốt hơn:

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

Làm thế nào tôi có thể cải thiện điều này? Tôi xin lỗi nếu đây là một bản sao, có rất nhiều chủ đề phản ánh ngoài kia ... có vẻ như đó là một chủ đề khá nóng.


Không. Bạn cần một PropertyInfo trước khi bạn có thể tìm hiểu xem thuộc tính có thuộc tính hay không.
Hans Passant

Câu trả lời:


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

Điều này tránh việc phải cụ thể hóa bất kỳ trường hợp thuộc tính nào (tức là nó rẻ hơn GetCustomAttribute[s]().


1
Gợi ý tốt. Tuy nhiên tôi sẽ cần ví dụ thuộc tính, nhưng tôi thích nó.
wsanville

1
Tôi chỉ tìm cách để kiểm tra sự tồn tại của một thuộc tính mà không có tác dụng phụ mà thuộc tính nhận được được gọi. Cảm ơn Marc, nó hoạt động!
janrjan Jämte

1
@ RjanJämte tài sản getkhông được gọi ngay cả khi sử dụng GetCustomAttributes; tuy nhiên, thuộc tính được khởi tạo , không miễn phí. Nếu bạn không cần kiểm tra các giá trị cụ thể của thuộc tính, IsDefinedthì rẻ hơn. Và trong 4.5, có nhiều cách để kiểm tra dữ liệu khởi tạo mà không thực sự tạo ra bất kỳ trường hợp thuộc tính nào (mặc dù điều này chỉ dành cho các kịch bản rất cụ thể)
Marc Gravell


2
đối với lõi dotnet: var props = t.GetProperIES (). Trong đó (e => e.IsDefined (typeof (MyAttribution)));
Rtype

45

Giải pháp tôi sử dụng hầu hết dựa trên câu trả lời của Tomas Petricek. Tôi thường muốn làm một cái gì đó với cả thuộc tính và thuộc tính.

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 - "Tôi thường muốn làm một cái gì đó với cả thuộc tính và thuộc tính" là những gì tôi đang tìm kiếm - cảm ơn rất nhiều vì đã đăng câu trả lời của bạn!
Yawar Murtaza

34

Theo như tôi biết, không có cách nào tốt hơn khi làm việc với thư viện Reflection theo cách thông minh hơn. Tuy nhiên, bạn có thể sử dụng LINQ để làm cho mã đẹp hơn một chút:

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'

Tôi tin rằng điều này giúp bạn cấu trúc mã theo cách dễ đọc hơn.


13

Luôn có LINQ:

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

6

Nếu bạn thường xuyên xử lý các thuộc tính trong Reflection, việc xác định một số phương thức mở rộng là rất, rất thực tế. Bạn sẽ thấy rằng trong nhiều dự án ngoài kia. Cái này ở đây là cái tôi thường có:

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

mà bạn có thể sử dụng như typeof(Foo).HasAttribute<BarAttribute>();

Các dự án khác (ví dụ: MapMap) có các lớp ReflectionHelper chính thức sử dụng các cây Biểu thức để có một cú pháp tốt để nhận dạng, ví dụ như PropertyInfos. Cách sử dụng sau đó trông như thế:

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

2

Ngoài các câu trả lời trước: tốt hơn nên sử dụng phương pháp Any()thay vì kiểm tra độ dài của bộ sưu tập:

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

Ví dụ tại dotnetfiddle: https://dotnetfiddle.net/96mKep


@ cogumel0 Trước hết, chắc chắn .Any()không kiểm tra độ dài. Nhưng câu trả lời của tôi không phải là về các thuộc tính được tìm thấy với chính xác một thuộc tính. Thứ hai, tôi không chắc chắn rằng bạn đọc mã chính xác - .Anyphương thức được gọi là kết quả của GetCustomAttrubutesphương thức. Vì vậy, loại của propertiesWithMyAttributesẽ là tập hợp các thuộc tính. Kiểm tra ví dụ tại dotnetfiddle (Tôi thêm liên kết vào câu trả lời).
lệ phí

1
Bạn có thể thay thế .Where bằng .Any, kể từ .Any cũng cho phép lambdas.
PRman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.