【问题标题】:How do I read an attribute on a class at runtime?如何在运行时读取类的属性?
【发布时间】:2011-02-09 00:22:52
【问题描述】:

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

注意:DomainName 属性属于 DomainNameAttribute 类。

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

我要生成的内容:

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

【问题讨论】:

标签: c# generics custom-attributes


【解决方案1】:
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);

【讨论】:

  • 感谢您认真回答问题!
  • 这个扩展方法可以通过扩展 MemberInfo、Type 的基类和所有 - 或至少 大多数 - Type 的成员来进一步推广。这样做会打开它以允许从属性、字段甚至事件中读取属性。
  • 过于复杂。无需使用 lambda 来选择属性值。如果您足够编写 lambda,那么您就可以访问该字段。
  • 我如何扩展这种方法以在静态类中获得const Filed
【解决方案2】:
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);
    }   
}

【讨论】:

  • 并且 +1 表示不使用“var”,因此很容易理解它的工作原理。
  • 它无法编译。但是“System.Reflection.MemberInfo info = typeof(MyClass).GetTypeInfo();”做
【解决方案3】:

我使用 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);

【讨论】:

【解决方案4】:

Darin Dimitrov 的第一个解决方案的简化版本:

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

【讨论】:

    【解决方案5】:
    ' 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.
    

    【讨论】:

      【解决方案6】:

      已经有一个扩展可以做到这一点。

      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 : "";
      

      【讨论】:

      • 是的。但只有 .NET 4.5 和更新版本。我仍在开发无法使用此方法的库代码:(
      【解决方案7】:

      如果有人需要一个可以为空的结果,并且它可以跨枚举、PropertyInfo 和类工作,这就是我解决它的方法。这是对 Darin Dimitrov 的更新解决方案的修改。

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

      【讨论】:

        【解决方案8】:

        与其写很多代码,不如这样:

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

        【讨论】:

          【解决方案9】:

          当你有同名的重写方法时使用下面的帮助器

          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 someController = new SomeController(Some params);变量 str = typeof(SomeController).GetControllerMethodAttributeValue(x => someController.SomeMethod(It.IsAny()), (RouteAttribute routeAttribute) => routeAttribute.Template);

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-11-19
            • 1970-01-01
            • 2011-08-05
            • 1970-01-01
            相关资源
            最近更新 更多