Çalışma zamanında bir sınıftaki bir özniteliği nasıl okuyabilirim?


107

Bir sınıftaki bir özniteliği okuyacak ve çalışma zamanında bu değeri döndürecek genel bir yöntem oluşturmaya çalışıyorum. Bunu nasıl yaparım?

Not: EtkiAlanıAdı özniteliği EtkiAlanıAdı Özniteliği sınıfındandır.

[DomainName("MyTable")]
Public class MyClass : DomainBase
{}

Oluşturmaya çalıştığım şey:

//This should return "MyTable"
String DomainNameValue = GetDomainName<MyClass>();

1
Resmi microsoft bağlantısı: msdn.microsoft.com/en-us/library/71s1zwct.aspx
Mahesh

2
Tüm türlerin özel öznitelik stackoverflow.com/questions/2656189/…
Chris Marisic

Yanıtlar:


236
public string GetDomainName<T>()
{
    var dnAttribute = typeof(T).GetCustomAttributes(
        typeof(DomainNameAttribute), true
    ).FirstOrDefault() as DomainNameAttribute;
    if (dnAttribute != null)
    {
        return dnAttribute.Name;
    }
    return null;
}

GÜNCELLEME:

Bu yöntem, herhangi bir öznitelikle çalışmak için daha da genelleştirilebilir:

public static class AttributeExtensions
{
    public static TValue GetAttributeValue<TAttribute, TValue>(
        this Type type, 
        Func<TAttribute, TValue> valueSelector) 
        where TAttribute : Attribute
    {
        var att = type.GetCustomAttributes(
            typeof(TAttribute), true
        ).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
}

ve bunun gibi kullanın:

string name = typeof(MyClass)
    .GetAttributeValue((DomainNameAttribute dna) => dna.Name);

6
Soruyu yanıtlarken gösterdiğiniz özen için teşekkür ederiz!
Zaffiro

1
Bu uzantı yöntemi, bir Tip temel sınıfı olan MemberInfo'nun ve bir Türün üyelerinin tümü veya en azından çoğu tarafından genişletilerek daha da genelleştirilebilir . Bunu yapmak, Özellikler, Alanlar ve hatta Olaylardan özniteliklerin okunmasına izin vermek için bunu açar.
M.Babcock

4
Aşırı karmaşık. Öznitelik değerini seçmek için lambda kullanmaya gerek yoktur. Lambda yazacak kadar yeterliyse, alana erişecek kadar bilginiz vardır.
Darrel Lee

Bu yaklaşımı const Filedstatik sınıfa geçmek için nasıl genişletebilirim ?
Amir

51

Bunu yapacak bir uzantı zaten var.

namespace System.Reflection
{
    // Summary:
    //     Contains static methods for retrieving custom attributes.
    public static class CustomAttributeExtensions
    {
        public static T GetCustomAttribute<T>(this MemberInfo element, bool inherit) where T : Attribute;
    }
}

Yani:

var attr = typeof(MyClass).GetCustomAttribute<DomainNameAttribute>(false);
return attr != null ? attr.DomainName : "";

1
Doğru. Ancak yalnızca .NET 4.5 ve daha yenisi. Hala bu yöntemi kullanamadığım bir kütüphane kodu geliştiriyorum :(
andreas

15
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);

for (int i = 0; i < attributes.Length; i++)
{
    if (attributes[i] is DomainNameAttribute)
    {
        System.Console.WriteLine(((DomainNameAttribute) attributes[i]).Name);
    }   
}

5
Ve "var" kullanmadığınız için +1, böylece nasıl çalıştığını anlamak kolaydır.
RenniePet

Derlemez. Ancak "System.Reflection.MemberInfo info = typeof (MyClass) .GetTypeInfo ();" do
Marcel James

4

Darin Dimitrov'un cevabını, bir sınıftaki herhangi bir üye için üye özniteliklerini elde etmek için genel bir uzantı oluşturmak için kullandım (bir sınıfın öznitelikleri yerine). Buraya gönderiyorum çünkü diğerleri onu faydalı bulabilir:

public static class AttributeExtensions
{
    /// <summary>
    /// Returns the value of a member attribute for any member in a class.
    ///     (a member is a Field, Property, Method, etc...)    
    /// <remarks>
    /// If there is more than one member of the same name in the class, it will return the first one (this applies to overloaded methods)
    /// </remarks>
    /// <example>
    /// Read System.ComponentModel Description Attribute from method 'MyMethodName' in class 'MyClass': 
    ///     var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);
    /// </example>
    /// <param name="type">The class that contains the member as a type</param>
    /// <param name="MemberName">Name of the member in the class</param>
    /// <param name="valueSelector">Attribute type and property to get (will return first instance if there are multiple attributes of the same type)</param>
    /// <param name="inherit">true to search this member's inheritance chain to find the attributes; otherwise, false. This parameter is ignored for properties and events</param>
    /// </summary>    
    public static TValue GetAttribute<TAttribute, TValue>(this Type type, string MemberName, Func<TAttribute, TValue> valueSelector, bool inherit = false) where TAttribute : Attribute
    {
        var att = type.GetMember(MemberName).FirstOrDefault().GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault() as TAttribute;
        if (att != null)
        {
            return valueSelector(att);
        }
        return default(TValue);
    }
}

Kullanım örneği:

//Read System.ComponentModel Description Attribute from method 'MyMethodName' in class 'MyClass'
var Attribute = typeof(MyClass).GetAttribute("MyMethodName", (DescriptionAttribute d) => d.Description);

Kalıtım türetilmiş özellikler üzerinde çalışmaz - bunun için ayrı bir statik yöntem çağırmanız gerekir (System.Attribute.GetCustomAttributes) stackoverflow.com/a/7175762/184910
murraybiscuit

3

Darin Dimitrov'un ilk çözümünün basitleştirilmiş bir versiyonu:

public string GetDomainName<T>()
{
    var dnAttribute = typeof(T).GetCustomAttribute<DomainNameAttribute>(true);
    if (dnAttribute != null)
    {
        return dnAttribute.Name;
    }
    return null;
}


0
' Simplified Generic version. 
Shared Function GetAttribute(Of TAttribute)(info As MemberInfo) As TAttribute
    Return info.GetCustomAttributes(GetType(TAttribute), _
                                    False).FirstOrDefault()
End Function

' Example usage over PropertyInfo
Dim fieldAttr = GetAttribute(Of DataObjectFieldAttribute)(pInfo)
If fieldAttr IsNot Nothing AndAlso fieldAttr.PrimaryKey Then
    keys.Add(pInfo.Name)
End If

Muhtemelen inline genel işlev gövdesini kullanmak kadar kolaydır. Fonksiyonu MyClass türü üzerinde jenerik yapmak bana hiç mantıklı gelmiyor.

string DomainName = GetAttribute<DomainNameAttribute>(typeof(MyClass)).Name
// null reference exception if MyClass doesn't have the attribute.

0

Herhangi birinin boş değer atanabilir bir sonuca ihtiyacı olması durumunda ve bunun Enums, PropertyInfo ve sınıflarda çalışması için, işte bunu nasıl çözdüm. Bu, Darin Dimitrov'un güncellenmiş çözümünün bir modifikasyonudur.

public static object GetAttributeValue<TAttribute, TValue>(this object val, Func<TAttribute, TValue> valueSelector) where TAttribute : Attribute
{
    try
    {
        Type t = val.GetType();
        TAttribute attr;
        if (t.IsEnum && t.GetField(val.ToString()).GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() is TAttribute att)
        {
            // Applies to Enum values
            attr = att;
        }
        else if (val is PropertyInfo pi && pi.GetCustomAttributes(typeof(TAttribute), true).FirstOrDefault() is TAttribute piAtt)
        {
            // Applies to Properties in a Class
            attr = piAtt;
        }
        else
        {
            // Applies to classes
            attr = (TAttribute)t.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault();
        }
        return valueSelector(attr);
    }
    catch
    {
        return null;
    }
}

Kullanım örnekleri:

// Class
SettingsEnum.SettingGroup settingGroup = (SettingsEnum.SettingGroup)(this.GetAttributeValue((SettingGroupAttribute attr) => attr.Value) as SettingsEnum.SettingGroup?);

// Enum
DescriptionAttribute desc = settingGroup.GetAttributeValue((DescriptionAttribute attr) => attr) as DescriptionAttribute;

// PropertyInfo       
foreach (PropertyInfo pi in this.GetType().GetProperties())
{
    string setting = ((SettingsEnum.SettingName)(pi.GetAttributeValue((SettingNameAttribute attr) => attr.Value) as SettingsEnum.SettingName?)).ToString();
}

0

Bunun yerine çok sayıda kod yazın, sadece şunu yapın:

{         
   dynamic tableNameAttribute = typeof(T).CustomAttributes.FirstOrDefault().ToString();
   dynamic tableName = tableNameAttribute.Substring(tableNameAttribute.LastIndexOf('.'), tableNameAttribute.LastIndexOf('\\'));    
}

0

Aynı Ada Sahip Yöntemleri Geçersiz Kıldıysanız Aşağıdaki yardımcıyı kullanın

public static TValue GetControllerMethodAttributeValue<T, TT, TAttribute, TValue>(this T type, Expression<Func<T, TT>> exp, Func<TAttribute, TValue> valueSelector) where TAttribute : Attribute
        {
            var memberExpression = exp?.Body as MethodCallExpression;

            if (memberExpression.Method.GetCustomAttributes(typeof(TAttribute), false).FirstOrDefault() is TAttribute attr && valueSelector != null)
            {
                return valueSelector(attr);
            }

            return default(TValue);
        }

Kullanım: var someController = new SomeController (Bazı parametreler); var str = typeof (SomeController) .GetControllerMethodAttributeValue (x => someController.SomeMethod (It.IsAny ()), (RouteAttribute routeAttribute) => routeAttribute.Template);

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.