2010-04-16 11 views
68

Estoy intentando crear un método genérico que leerá un atributo en una clase y devolverá ese valor en tiempo de ejecución. ¿Cómo puedo hacer esto?¿Cómo leo un atributo en una clase en tiempo de ejecución?

Nota: El atributo DomainName es de la clase DomainNameAttribute.

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

lo que estoy tratando de generar:

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

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

+2

cuestión importante corolario cómo conseguir todo tipo de montaje con atributo personalizado http://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime –

Respuesta

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

ACTUALIZACIÓN:

Este método podría generalizarse aún más para trabajar con cualquier atributo:

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

y el uso de la siguiente manera:

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

¡Gracias por su diligencia al responder la pregunta! – Zaffiro

+1

Este método de extensión podría generalizarse más ampliando MemberInfo, una clase base de Type y todos, o al menos * la mayoría *, de los miembros de Type. Hacerlo abriría esto para permitir la lectura de atributos desde Propiedades, Campos e incluso Eventos. –

+2

excesivamente complicado. No es necesario usar lambda para seleccionar el valor del atributo.Si tienes suficiente para escribir el lambda, sabes lo suficiente como para acceder al campo. –

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 solución de Darin es más elegante. – Merritt

+0

+1 por su esfuerzo pensó –

+1

Y +1 por no usar "var", por lo que es fácil de entender cómo funciona. – RenniePet

4

utilicé la respuesta de Darin Dimitrov para crear una extensión genérica para obtener atributos de miembro para cualquier miembro de una clase (en lugar de atribuirlo) es para una clase). Les dejo aquí porque para otros puede ser útil: ejemplo

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

Uso:

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

La herencia no funciona en propiedades derivadas; para eso, deberá llamar a un método estático separado (System.Attribute.GetCustomAttributes) http://stackoverflow.com/a/7175762/184910 – murraybiscuit

2

una versión simplificada de la primera solución 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 

Probablemente tan fácil de usar el cuerpo de la función genérica en línea. No tiene ningún sentido para mí hacer que la función sea genérica sobre el tipo MyClass.

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

Ya existe una extensión para hacer esto.

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

Así:

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