ตรวจสอบว่าทรัพย์สินมีคุณสมบัติ


158

ให้คุณสมบัติในคลาสพร้อมกับคุณสมบัติ - วิธีที่เร็วที่สุดในการพิจารณาว่ามันมีคุณสมบัติที่กำหนดคืออะไร? ตัวอย่างเช่น:

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

วิธีที่เร็วที่สุดในการพิจารณาคือตัวอย่างเช่นมีแอตทริบิวต์ "IsIdentity"?

คำตอบ:


279

ไม่มีวิธีที่รวดเร็วในการดึงข้อมูลแอตทริบิวต์ แต่รหัสควรมีลักษณะเช่นนี้ (เครดิตกับAaronaught ):

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

หากคุณต้องการเรียกคืนคุณสมบัติของคุณสมบัตินั้น

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
หากคุณต้องการตรวจสอบว่ามีแอตทริบิวต์อยู่หรือไม่และไม่สามารถดึงข้อมูลใด ๆ ได้การใช้Attribute.IsDefinedจะกำจัดรหัสหนึ่งบรรทัดและอาร์เรย์ / แคสต์ที่น่าเกลียด
Aaronaught

4
สิ่งที่ฉันเพิ่งพบกับสิ่งนี้คือคุณลักษณะบางอย่างมีประเภทที่แตกต่างกับชื่อคุณลักษณะ ตัวอย่างเช่น "NotMapped" ใน System.ComponentModel.DataAnnotations.Schema ถูกนำมาใช้[NotMapped]ในชั้นเรียน แต่เพื่อตรวจสอบว่าคุณต้องใช้Attribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
อาจจะใช้งานโอเวอร์โหลดทั่วไปได้ง่ายกว่า:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba

@Qjimbo (หรืออาจเป็นคนอื่นอ่าน) แอตทริบิวต์มักจะใช้โดยไม่ต้องส่วน "แอตทริบิวต์" ของชื่อของพวกเขา แต่สามารถ อนุสัญญาอนุญาตให้คุณยกเว้นได้ดังนั้นโดยปกติประเภทที่แท้จริงจะมีแอททริบิวท้ายชื่อ แต่ไม่ได้ใช้
Jim Wolff

44

หากคุณใช้. NET 3.5 คุณอาจลองใช้ต้นไม้ Expression มันปลอดภัยกว่าการสะท้อน:

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
มีคำถามที่ถามเกี่ยวกับคำตอบของคุณ stackoverflow.com/questions/4158996/…
Greg

12

คุณสามารถใช้วิธีการทั่วไป (ทั่วไป) เพื่ออ่านคุณสมบัติผ่าน MemberInfo ที่กำหนด

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

หากต้องการอัปเดตและ / หรือปรับปรุงคำตอบโดย @Hans Passant ฉันจะแยกการดึงข้อมูลคุณสมบัติออกเป็นวิธีส่วนขยาย สิ่งนี้มีประโยชน์เพิ่มเติมในการลบสตริงมายากลที่น่ารังเกียจในวิธีการ 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();
        }
    }
}

การทดสอบของคุณจะถูกลดเหลือสองบรรทัด

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

7

หากคุณพยายามทำเช่นนั้นใน Portable Class Library PCL (เช่นฉัน) นี่คือวิธีที่คุณทำได้ :)

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());

จากนั้นคุณสามารถตรวจสอบจำนวนของคุณสมบัติที่มีคุณสมบัติพิเศษนี้หากคุณต้องการ


7

ตอนนี้สามารถทำได้โดยไม่ต้องมีต้นไม้แสดงออกและวิธีการขยายอย่างปลอดภัยชนิดด้วยคุณสมบัติ C # ใหม่nameof()เช่นนี้:

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

nameof ()ถูกนำมาใช้ใน C # 6


6

คุณสามารถใช้วิธีการ Attribute.IsDefined

https://msdn.microsoft.com/en-us/library/system.attribute.isdefined(v=vs.110).aspx

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

คุณสามารถระบุสถานที่ให้บริการที่คุณกำลังมองหาโดยเฉพาะหรือคุณสามารถทำซ้ำสิ่งเหล่านี้โดยใช้การสะท้อนความเห็น:

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

สิ่งนี้ไม่ได้รวบรวม คุณไม่สามารถใช้ [] รอบ YourProperty หรือ YourAttribute
ม้วน

คำตอบก่อนหน้านี้ทุกข้อใช้สมมติฐานเกี่ยวกับคลาสทรัพย์สินและชื่อคุณสมบัติที่ฉันติดตาม
Francis Musignac

แก้ไขแล้ว
ม้วน

2

นี่เป็นคำถามที่ค่อนข้างเก่า แต่ฉันใช้

วิธีการของฉันมีพารามิเตอร์นี้ แต่มันสามารถสร้างได้:

Expression<Func<TModel, TValue>> expression

จากนั้นในวิธีนี้:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.