Özelliğin özelliğine sahip olup olmadığını kontrol edin


158

Sınıfta, nitelikleri olan bir özellik verildiğinde, belirli bir özellik içerip içermediğini belirlemenin en hızlı yolu nedir? Örneğin:

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

Örneğin "IsIdentity" özniteliğine sahip olduğunu belirlemenin en hızlı yöntemi nedir?

Yanıtlar:


280

Nitelikleri almanın hızlı bir yolu yoktur. Ancak kod şöyle görünmelidir ( Aaronaught'a verilen kredi ):

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

Özellik özelliklerini almanız gerekiyorsa

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
Özniteliğin varlığını kontrol etmeniz ve ondan herhangi bir bilgi almamanız gerekiyorsa, kullanmak Attribute.IsDefinedbir satır kod ve çirkin dizileri / dökümleri ortadan kaldırır.
Aaronaught

4
Sadece bununla karşılaştığım bir şey, bazı niteliklerin özellik adlarından farklı bir türü var. Örneğin, System.ComponentModel.DataAnnotations.Schema'daki "NotMapped" [NotMapped]sınıfta olduğu gibi kullanılır, ancak bunu algılamak için kullanmanız gerekirAttribute.IsDefined(pi, typeof(NotMappedAttribute))
Qjimbo

2
Genel aşırı yükü kullanmak daha kolay olabilir:IsIdentity[] attr = pi.GetCustomAttributes<IsIdentity>(false);
Mojtaba

@Qjimbo (veya muhtemelen okuyan başka biri) Nitelikler genellikle adlarının "Nitelik" kısmı olmadan kullanılır, ancak olabilir. Bir kural bunu dışlamanıza izin verir, bu nedenle genellikle gerçek türün adının sonunda Nitelik vardır, ancak kullanılmaz.
Jim Wolff

44

.NET 3.5 kullanıyorsanız İfade ağaçları ile deneyebilirsiniz. Yansımadan daha güvenlidir:

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
Cevabınız hakkında bir soru soruldu. stackoverflow.com/questions/4158996/…
Greg

12

Belirli bir MemberInfo üzerinden özniteliği okumak için ortak (genel) bir yöntem kullanabilirsiniz

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

Cevabı @Hans Passant ile güncellemek ve / veya geliştirmek için özelliğin geri çağrılmasını bir uzatma yöntemine ayırırım. Bu GetProperty () yönteminde kötü sihirli dize kaldırma ek bir yararı vardır

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

Testiniz daha sonra iki satıra indirilir

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

7

Bunu bir Taşınabilir Sınıf Kütüphanesi PCL'sinde (benim gibi) yapmaya çalışıyorsanız, bunu nasıl yapabilirsiniz :)

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

Daha sonra, gerekirse bu özel özelliğe sahip özelliklerin sayısını kontrol edebilirsiniz.


7

Bu artık ifade ağaçları ve genişletme yöntemleri olmadan yeni C # özelliği ile güvenli bir şekilde yapılabilir nameof():

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

nameof () C # 6'da tanıtıldı


6

Attribute.IsDefined yöntemini kullanabilirsiniz

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

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

Özellikle aradığınız mülkü sağlayabilir veya tümünü yansıma kullanarak tekrarlayabilirsiniz:

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

Bu derlenmiyor. Sen kullanamazsınız [] YourProperty veya YourAttribute etrafında
rulo

Önceki her yanıt, takip ettiğim sınıf, mülk ve nitelik adları üzerinde varsayımlar kullandı.
Francis Musignac

Şimdi düzeltildi.
rulolar

2

Bu oldukça eski bir soru ama kullandım

Benim yöntem bu parametre var ama inşa edilebilir:

Expression<Func<TModel, TValue>> expression

Sonra yöntemde bu:

System.Linq.Expressions.MemberExpression memberExpression 
       = expression.Body as System.Linq.Expressions.MemberExpression;
Boolean hasIdentityAttr = System.Attribute
       .IsDefined(memberExpression.Member, typeof(IsIdentity));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.