How do I read an attribute on a class at runtime?

浪子不回头ぞ 提交于 2019-11-26 03:26:52

问题


I am trying to create a generic method that will read an attribute on a class and return that value at runtime. How do would I do this?

Note: DomainName attribute is of class DomainNameAttribute.

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

What I am trying to generate:

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

回答1:


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

UPDATE:

This method could be further generalized to work with any attribute:

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

and use like this:

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



回答2:


There is already an extension to do this.

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

So:

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



回答3:


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



回答4:


I used Darin Dimitrov's answer to create a generic extension to get member attributes for any member in a class (instead of attributes for a class). I'm posting it here because others may find it useful:

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

Usage example:

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



回答5:


A simplified version of Darin Dimitrov's first solution:

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



回答6:


Here's a good tutorial if you haven't seen it before http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx

In particular of interest to you is the section here, called Accessing the Attribute http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx#vcwlkattributestutorialanchor3




回答7:


' 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

Probably just as easy to use the body of generic function inline. It doesn't make any sense to me to make the function generic over the type MyClass.

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



回答8:


In case anyone needs a nullable result and for this to work across Enums, PropertyInfo and classes, here's how I solved it. This is a modification of Darin Dimitrov's updated solution.

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

Usage examples:

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



回答9:


Rather then write a lot of code, just do this:

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


来源:https://stackoverflow.com/questions/2656189/how-do-i-read-an-attribute-on-a-class-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!