如何在运行时读取类的属性?

我尝试创建一个泛型方法,它将读取类的属性并在运行时返回该值。我该怎么做?

注意: DomainName 属性属于类 DomainNameAttribute.

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

我试图创造的东西:

//This should return "MyTable"
String DomainNameValue = GetDomainName<MyClass>();
145697 次浏览
public string GetDomainName<T>()
{
var dnAttribute = typeof(T).GetCustomAttributes(
typeof(DomainNameAttribute), true
).FirstOrDefault() as DomainNameAttribute;
if (dnAttribute != null)
{
return dnAttribute.Name;
}
return null;
}

更新:

这种方法可以进一步推广到任何属性:

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

像这样使用:

string name = typeof(MyClass)
.GetAttributeValue((DomainNameAttribute dna) => dna.Name);
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);
}
}

我使用 Darin Dimitrov 的答案创建了一个通用扩展来获取类中任何成员的成员属性(而不是类的属性)。我把它贴在这里是因为其他人可能会觉得它很有用:

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

用法例子:

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

达林•迪米特洛夫(Darin Dimitrov)第一个解决方案的简化版:

public string GetDomainName<T>()
{
var dnAttribute = typeof(T).GetCustomAttribute<DomainNameAttribute>(true);
if (dnAttribute != null)
{
return dnAttribute.Name;
}
return null;
}
' 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

也许就像内联使用泛型函数体一样简单。 对我来说,使函数通用于 MyClass 类型是没有任何意义的。

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

已经有一个扩展来做这件事。

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

所以:

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

如果有人需要一个可为空的结果,并且要在 Enums、 PropertyInfo 和类之间工作,以下是我解决这个问题的方法。这是对达林 · 迪米特洛夫的最新解决方案的修改。

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

用法例子:

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

与其编写大量代码,不如这样做:

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

当您有相同名称的重写方法时,请使用下面的帮助器

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

用法: var Some Controller = new Some Controller (Some params) ; var str = Typeof (Some Controller) . GetControllerMethodAttributeValue (x = > 方法(It. Isany ()) ,(RouteAttribute RouteAttribute) = > routeAttribute. Template) ;