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"?

Otávio Décio
sumber

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
}
Hans Passant
sumber
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;
    }
}
Darin Dimitrov
sumber
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;
            }
Manish Basantani
sumber
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));
Seb
sumber
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.

Memiliki AlTaiar
sumber
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

Jim Wolff
sumber
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();
Francis Musignac
sumber
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));
Mark Schultheiss
sumber