2010-04-16 3 views
68

J'essaye de créer une méthode générique qui lira un attribut sur une classe et renverra cette valeur à l'exécution. Comment est-ce que je ferais ceci?Comment lire un attribut sur une classe lors de l'exécution?

Remarque: l'attribut DomainName est de la classe DomainNameAttribute.

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

Ce que je suis en train de générer:

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

lien officiel de Microsoft: http://msdn.microsoft.com/en-us/library/71s1zwct.aspx – Mahesh

+2

question corollaire Important comment obtenir tous les types de montage avec attribut personnalisé http://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime –

Répondre

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

MISE À JOUR:

Cette méthode pourrait encore être généralisé à travailler avec tous les attributs:

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

et utiliser comme ceci:

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

Merci de votre diligence pour répondre à la question! – Zaffiro

+1

Cette méthode d'extension pourrait être généralisée en élargissant MemberInfo, une classe de base de Type et tous - ou au moins * la plupart * - des membres d'un Type. Cela ouvrirait cela pour permettre la lecture des attributs depuis les propriétés, les champs et même les événements. –

+2

Trop compliqué. Il n'est pas nécessaire d'utiliser lambda pour sélectionner la valeur de l'attribut.Si vous avez assez d'écrire le lambda, vous en savez assez pour accéder au champ. –

9
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); 
    } 
} 
+3

@Anyone: La solution de Darin est plus élégante. – Merritt

+0

+1 pour vous effort pensé –

+1

Et +1 pour ne pas utiliser "var", donc il est facile de comprendre comment cela fonctionne. – RenniePet

4

je la réponse de Darin Dimitrov pour créer une extension générique pour obtenir des attributs de membre pour n'importe quel membre d'une classe (au lieu d'attribuer es pour une classe). Je poste ici parce que d'autres peuvent trouver utiles:

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

Exemple d'utilisation:

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

L'héritage ne fonctionne pas sur les propriétés dérivées - pour cela, vous devrez appeler une méthode statique distincte (System.Attribute.GetCustomAttributes) http://stackoverflow.com/a/7175762/184910 – murraybiscuit

2

Une version simplifiée de la première solution de Darin Dimitrov:

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 

Probablement tout aussi facile à utiliser le corps de la fonction générique inline. Cela n'a aucun sens pour moi de rendre la fonction générique sur le type MyClass.

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

Il existe déjà une extension pour cela.

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

Alors:

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