Periksa apakah properti memiliki atribut


158

Diberikan properti di kelas, dengan atribut - apa cara tercepat untuk menentukan apakah itu berisi atribut yang diberikan? Sebagai contoh:

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

Apa metode tercepat untuk menentukan bahwa misalnya ia memiliki atribut "IsIdentity"?

Jawaban:


280

Tidak ada cara cepat untuk mengambil atribut. Tetapi kode harus terlihat seperti ini (kredit untuk Aaronaught ):

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

Jika Anda perlu mengambil properti atribut, maka

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
Jika Anda hanya perlu memeriksa keberadaan atribut, dan tidak mengambil informasi apa pun darinya, menggunakan Attribute.IsDefinedakan menghilangkan satu baris kode dan array / casting yang jelek.
Aaronaught

4
Sesuatu yang baru saja saya temui adalah beberapa atribut memiliki tipe yang berbeda dengan nama atributnya. Misalnya "NotMapped" di System.ComponentModel.DataAnnotations.Schema digunakan seperti [NotMapped]di kelas tetapi untuk mendeteksinya Anda harus menggunakanAttribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
Mungkin lebih mudah menggunakan overload generik:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba

@ Qjimbo (atau mungkin orang lain membaca) Atribut biasanya digunakan tanpa bagian "Atribut" dari nama mereka, tetapi bisa saja. Sebuah konvensi memungkinkan Anda untuk mengecualikannya, jadi biasanya tipe yang sebenarnya memiliki Atribut di akhir namanya, tetapi tidak digunakan.
Jim Wolff

44

Jika Anda menggunakan .NET 3.5 Anda dapat mencoba dengan pohon Ekspresi. Ini lebih aman daripada refleksi:

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 pertanyaan telah diajukan tentang jawaban Anda. stackoverflow.com/questions/4158996/…
Greg

12

Anda dapat menggunakan metode umum (generik) untuk membaca atribut melalui MemberInfo yang diberikan

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

Untuk memperbarui dan / atau meningkatkan jawaban oleh @Hans Passant, saya akan memisahkan pengambilan properti menjadi metode ekstensi. Ini memiliki manfaat tambahan dari menghilangkan string sihir jahat dalam metode 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();
        }
    }
}

Tes Anda kemudian dikurangi menjadi dua baris

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

7

Jika Anda mencoba melakukan itu di Portable Class Library PCL (seperti saya), maka inilah cara Anda dapat melakukannya :)

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

Anda kemudian dapat memeriksa jumlah properti yang memiliki properti khusus ini jika perlu.


7

Ini sekarang dapat dilakukan tanpa pohon ekspresi dan metode ekstensi dalam jenis yang aman dengan fitur C # baru nameof()seperti ini:

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

nameof () diperkenalkan di C # 6


6

Anda dapat menggunakan metode Attribute.IsDefined

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

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

Anda dapat memberikan properti yang Anda cari secara spesifik atau Anda dapat menggunakannya kembali menggunakan refleksi, seperti:

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

Ini tidak dikompilasi. Anda tidak dapat menggunakan [] di sekitar YourProperty atau YourAttribute
rolls

Setiap jawaban sebelumnya menggunakan asumsi pada kelas, properti, dan nama atribut yang saya ikuti.
Francis Musignac

Muncul diperbaiki sekarang.
gulungan

2

Ini pertanyaan yang cukup lama tapi saya gunakan

Metode saya memiliki parameter ini tetapi dapat dibangun:

Expression<Func<TModel, TValue>> expression

Kemudian dalam metode ini:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.