Kiểm tra nếu thuộc tính có thuộc tính


158

Cho một thuộc tính trong một lớp, với các thuộc tính - cách nhanh nhất để xác định xem nó có chứa thuộc tính đã cho không? Ví dụ:

    [IsNotNullable]
    [IsPK]
    [IsIdentity]
    [SequenceNameAttribute("Id")]
    public Int32 Id
    {
        get
        {
            return _Id;
        }
        set
        {
            _Id = value;
        }
    }

Phương pháp nhanh nhất để xác định rằng ví dụ nó có thuộc tính "IsIdentity" là gì?

Câu trả lời:


279

Không có cách nào nhanh chóng để lấy các thuộc tính. Nhưng mã phải giống như thế này (tín dụng cho Aaronaught ):

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var hasIsIdentity = Attribute.IsDefined(pi, typeof(IsIdentity));

Nếu bạn cần lấy thuộc tính thì

var t = typeof(YourClass);
var pi = t.GetProperty("Id");
var attr = (IsIdentity[])pi.GetCustomAttributes(typeof(IsIdentity), false);
if (attr.Length > 0) {
    // Use attr[0], you'll need foreach on attr if MultiUse is true
}

63
Nếu bạn chỉ cần kiểm tra sự tồn tại của thuộc tính và không lấy bất kỳ thông tin nào từ nó, việc sử dụng Attribute.IsDefinedsẽ loại bỏ một dòng mã và các mảng / đúc xấu xí.
Aaronaught

4
Một cái gì đó tôi vừa gặp phải là một số thuộc tính có một loại khác với tên thuộc tính của chúng. Ví dụ: "NotMapped" trong System.ComponentModel.DataAnnotations.Schema được sử dụng như [NotMapped]trong lớp nhưng để phát hiện ra nó, bạn phải sử dụngAttribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo 13/07/18

2
Có thể dễ dàng hơn để sử dụng quá tải chung:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba

@Qjimbo (hoặc có thể là người khác đang đọc) Các thuộc tính thường được sử dụng mà không có phần "Thuộc tính" trong tên của chúng, nhưng có thể. Một quy ước cho phép bạn loại trừ nó, vì vậy thông thường loại thực tế có Thuộc tính ở cuối tên của nó, nhưng chỉ không được sử dụng.
Jim Wolff

44

Nếu bạn đang sử dụng .NET 3.5, bạn có thể thử với cây Expression. Nó an toàn hơn so với phản ánh:

class CustomAttribute : Attribute { }

class Program
{
    [Custom]
    public int Id { get; set; }

    static void Main()
    {
        Expression<Func<Program, int>> expression = p => p.Id;
        var memberExpression = (MemberExpression)expression.Body;
        bool hasCustomAttribute = memberExpression
            .Member
            .GetCustomAttributes(typeof(CustomAttribute), false).Length > 0;
    }
}

7
FYI một câu hỏi đã được hỏi về câu trả lời của bạn. stackoverflow.com/questions/4158996/ hy
Greg

12

Bạn có thể sử dụng một phương thức chung (chung) để đọc thuộc tính trên một MemberInfo đã cho

public static bool TryGetAttribute<T>(MemberInfo memberInfo, out T customAttribute) where T: Attribute {
                var attributes = memberInfo.GetCustomAttributes(typeof(T), false).FirstOrDefault();
                if (attributes == null) {
                    customAttribute = null;
                    return false;
                }
                customAttribute = (T)attributes;
                return true;
            }

7

Để cập nhật và / hoặc nâng cao câu trả lời của @Hans Passant, tôi sẽ tách việc truy xuất tài sản thành một phương thức mở rộng. Điều này có thêm lợi ích của việc loại bỏ chuỗi ma thuật khó chịu trong phương thức GetProperty ()

public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}

Bài kiểm tra của bạn sau đó được giảm xuống còn hai dòng

var property = PropertyHelper<MyClass>.GetProperty(x => x.MyProperty);
Attribute.IsDefined(property, typeof(MyPropertyAttribute));

7

Nếu bạn đang cố gắng làm điều đó trong Thư viện lớp di động PCL (như tôi), thì đây là cách bạn có thể làm điều đó :)

public class Foo
{
   public string A {get;set;}

   [Special]
   public string B {get;set;}   
}

var type = typeof(Foo);

var specialProperties = type.GetRuntimeProperties()
     .Where(pi => pi.PropertyType == typeof (string) 
      && pi.GetCustomAttributes<Special>(true).Any());

Sau đó, bạn có thể kiểm tra số lượng tài sản có thuộc tính đặc biệt này nếu bạn cần.


7

Điều này bây giờ có thể được thực hiện mà không cần cây biểu thức và phương thức mở rộng theo cách an toàn với tính năng C # mới nameof()như thế này:

Attribute.IsDefined(typeof(YourClass).GetProperty(nameof(YourClass.Id)), typeof(IsIdentity));

nameof () đã được giới thiệu trong C # 6


6

Bạn có thể sử dụng phương thức Attribution.IsDefined

https://msdn.microsoft.com/en-us/l Library / system.attribution. thẩm định (v = vs.110) .aspx

if(Attribute.IsDefined(YourProperty,typeof(YourAttribute)))
{
    //Conditional execution...
}

Bạn có thể cung cấp tài sản mà bạn đang tìm kiếm cụ thể hoặc bạn có thể lặp qua tất cả chúng bằng cách sử dụng sự phản chiếu, đại loại như:

PropertyInfo[] props = typeof(YourClass).GetProperties();

Điều này không biên dịch. Bạn không thể sử dụng [] xung quanh YourProperty hoặc YourAttribution
cuộn

Mỗi câu trả lời trước đã sử dụng các giả định về tên lớp, thuộc tính và thuộc tính mà tôi đã theo dõi.
Francis Musignac

Xuất hiện cố định bây giờ.
cuộn

2

Đây là một câu hỏi khá cũ nhưng tôi đã sử dụng

Phương thức của tôi có tham số này nhưng nó có thể được xây dựng:

Expression<Func<TModel, TValue>> expression

Sau đó, trong phương thức này:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
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.