【问题标题】:Custom attribute on property - Getting type and value of attributed property属性上的自定义属性 - 获取属性属性的类型和值
【发布时间】:2011-03-18 09:08:38
【问题描述】:

我有以下自定义属性,可以应用于属性:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IdentifierAttribute : Attribute
{
}

例如:

public class MyClass
{
    [Identifier()]
    public string Name { get; set; }

    public int SomeNumber { get; set; }
    public string SomeOtherProperty { get; set; }
}

还有其他类,可以将 Identifier 属性添加到不同类型的属性中:

public class MyOtherClass
{
    public string Name { get; set; }

    [Identifier()]
    public int SomeNumber { get; set; }

    public string SomeOtherProperty { get; set; }
}

然后我需要能够在我的消费类中获取这些信息。 例如:

public class TestClass<T>
{
    public void GetIDForPassedInObject(T obj)
    {
        var type = obj.GetType();
        //type.GetCustomAttributes(true)???
    }
}

解决这个问题的最佳方法是什么? 我需要获取 [Identifier()] 字段的类型(int、string 等)和实际值,显然基于类型。

【问题讨论】:

    标签: c# .net custom-attributes


    【解决方案1】:

    如下所示,这将只使用它遇到的第一个具有该属性的属性,当然你可以将它放在多个..

        public object GetIDForPassedInObject(T obj)
        {
            var prop = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
                       .FirstOrDefault(p => p.GetCustomAttributes(typeof(IdentifierAttribute), false).Count() ==1);
            object ret = prop !=null ?  prop.GetValue(obj, null) : null;
    
            return ret;
        }  
    

    【讨论】:

    • 谢谢 - 不能在 FirstOrDefault 的 lambda 中使用“prop”,但我已经对其进行了排序 :-)
    • 啊,是的,是用记事本写的 ;-) 已修复。
    • 我已经用 [Identifier()] 标记了我的属性,但是 .GetProperties() 返回所有其他属性,除了这个?!我的属性似乎隐藏了它??
    • 尝试指定GetProperties(BindingFlags.Public | BindingFlags.Instance)等绑定标志;
    【解决方案2】:
    public class TestClass<T>
    {
        public void GetIDForPassedInObject(T obj)
        {
            PropertyInfo[] properties =
                obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);            
    
            PropertyInfo IdProperty = (from PropertyInfo property in properties
                               where property.GetCustomAttributes(typeof(Identifier), true).Length > 0
                               select property).First();
    
             if(null == IdProperty)
                 throw new ArgumentException("obj does not have Identifier.");
    
             Object propValue = IdProperty.GetValue(entity, null)
        }
    }
    

    【讨论】:

      【解决方案3】:

      有点晚了,但这是我为枚举所做的事情(也可以是任何对象)并使用扩展名获取描述属性值(这可能是任何属性的通用属性):

      public enum TransactionTypeEnum
      {
          [Description("Text here!")]
          DROP = 1,
      
          [Description("More text here!")]
          PICKUP = 2,
      
          ...
      }
      

      获取值:

      var code = TransactionTypeEnum.DROP.ToCode();
      

      支持我所有枚举的扩展:

      public static string ToCode(this TransactionTypeEnum val)
      {
          return GetCode(val);
      }
      
      public static string ToCode(this DockStatusEnum val)
      {
          return GetCode(val);
      }
      
      public static string ToCode(this TrailerStatusEnum val)
      {
          return GetCode(val);
      }
      
      public static string ToCode(this DockTrailerStatusEnum val)
      {
          return GetCode(val);
      }
      
      public static string ToCode(this EncodingType val)
      {
          return GetCode(val);
      }
      
      private static string GetCode(object val)
      {
          var attributes = (DescriptionAttribute[])val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
      
          return attributes.Length > 0 ? attributes[0].Description : string.Empty;
      }
      

      【讨论】:

      • 您知道在自定义 Attribute 类内部访问属性属性类型的方法吗?
      【解决方案4】:

      这是一个更真实的例子。我们使用扩展方法并检查属性是否包含 FieldMetaDataAttribute(我的源代码库中的自定义属性) 具有有效的主要和次要版本。一般感兴趣的是我们使用父类类型和 GetProperties 并检索 ProperyInfo,然后在这种特殊情况下使用 GetCustomAttribute 检索属性 FieldMetaDataAttribute 的部分。使用此代码来获取灵感,如何以更通用的方式检索自定义属性。当然,这可以被完善以创建一个通用方法来检索类实例的任何属性的给定属性。

              /// <summary>
          /// Executes the action if not the field is deprecated 
          /// </summary>
          /// <typeparam name="TProperty"></typeparam>
          /// <typeparam name="TForm"></typeparam>
          /// <param name="form"></param>
          /// <param name="memberExpression"></param>
          /// <param name="actionToPerform"></param>
          /// <returns>True if the action was performed</returns>
          public static bool ExecuteActionIfNotDeprecated<TForm, TProperty>(this TForm form, Expression<Func<TForm, TProperty>> memberExpression, Action actionToPerform)
          {
              var memberExpressionConverted = memberExpression.Body as MemberExpression;
              if (memberExpressionConverted == null)
                  return false; 
      
              string memberName = memberExpressionConverted.Member.Name;
      
      
              PropertyInfo matchingProperty = typeof(TForm).GetProperties(BindingFlags.Public | BindingFlags.Instance)
                  .FirstOrDefault(p => p.Name == memberName);
              if (matchingProperty == null)
                  return false; //should not occur
      
              var fieldMeta = matchingProperty.GetCustomAttribute(typeof(FieldMetadataAttribute), true) as FieldMetadataAttribute;
              if (fieldMeta == null)
              {
                  actionToPerform();
                  return true;
              }
      
              var formConverted = form as FormDataContract;
              if (formConverted == null)
                  return false;
      
              if (fieldMeta.DeprecatedFromMajorVersion > 0 && formConverted.MajorVersion > fieldMeta.DeprecatedFromMajorVersion)
              {
                  //major version of formConverted is deprecated for this field - do not execute action
                  return false;
              }
      
              if (fieldMeta.DeprecatedFromMinorVersion > 0 && fieldMeta.DeprecatedFromMajorVersion > 0
                                                           && formConverted.MinorVersion >= fieldMeta.DeprecatedFromMinorVersion
                                                           && formConverted.MajorVersion >= fieldMeta.DeprecatedFromMajorVersion)
                  return false; //the field is expired - do not invoke action 
              actionToPerform();
              return true;
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-20
        • 2010-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多