【问题标题】:Can an extension method be added to a class property to get the value of an attribute associated with the property?是否可以将扩展方法添加到类属性中以获取与该属性关联的属性的值?
【发布时间】:2011-08-12 01:28:32
【问题描述】:

我有几个分配了属性的类。我最感兴趣的是 FieldLength.MaxLength 值。

/// <summary>
/// Users
/// </summary>
[Table(Schema = "dbo", Name = "users"), Serializable]
public partial class Users
{

    /// <summary>
    /// Last name
    /// </summary>
    [Column(Name = "last_name", SqlDbType = SqlDbType.VarChar)]
    private string _LastName;
    [FieldLength(MaxLength=25), FieldNullable(IsNullable=false)]
    public string LastName
    {
        set { _LastName = value; }
        get { return _LastName; }
    }

}

我需要知道是否可以为我的类中的属性编写某种扩展方法以返回 FieldLength 属性的 MaxLength 值?

例如。我希望能够写出类似下面的东西……

Users user = new Users();
int lastNameMaxLength = user.LastName.MaxLength();

【问题讨论】:

  • C# 不支持属性本身的扩展方法;你能做的最好的事情就是在属性的返回类型上定义一个扩展方法,这不会实现你想要的。

标签: c# extension-methods custom-attributes propertyinfo


【解决方案1】:

不,这是不可能的。不过,您可以在 Users 上添加扩展方法:

public static int LastNameMaxLength(this Users user) {
    // get by reflection, return
}

【讨论】:

    【解决方案2】:

    为了节省打字,您可以进一步将 Jason 的扩展改进为类似的内容。

    public static void MaxLength<T>(this T obj, Expression<Func<T, object>> property)
    

    这样它将出现在所有对象上(除非您指定where T 限制),并且您拥有属性访问器的编译时安全实现,就像您将代码用作:

    user.MaxLength(u => u.LastName);
    

    【讨论】:

      【解决方案3】:

      没有。因为您建议的语法返回 LastName 属性的值,而不是属性本身。

      为了检索和使用属性,您需要使用反射,这意味着您需要了解属性本身。

      作为一个想法,您可以通过使用 LINQ 的表达式库来巧妙地实现这一点,但可以解析对象的属性。

      您可能会寻找的示例语法:

      var lastNameMaxLength = AttributeResolver.MaxLength<Users>(u => u.LastName);
      

      地点:

      public class AttributeResolver
      {
          public int MaxLength<T>(Expression<Func<T, object>> propertyExpression)
          {
              // Do the good stuff to get the PropertyInfo from the Expression...
              // Then get the attribute from the PropertyInfo
              // Then read the value from the attribute
          }
      }
      

      我发现这个类有助于解析表达式中的属性:

      public class TypeHelper
      {
          private static PropertyInfo GetPropertyInternal(LambdaExpression p)
          {
              MemberExpression memberExpression;
      
              if (p.Body is UnaryExpression)
              {
                  UnaryExpression ue = (UnaryExpression)p.Body;
                  memberExpression = (MemberExpression)ue.Operand;
              }
              else
              {
                  memberExpression = (MemberExpression)p.Body;
              }
              return (PropertyInfo)(memberExpression).Member;
          }
      
          public static PropertyInfo GetProperty<TObject>(Expression<Func<TObject, object>> p)
          {
              return GetPropertyInternal(p);
          }
      }
      

      【讨论】:

        【解决方案4】:

        这种形式是不可能的。您可以管理的最好方法是采用 lambda 表达式,获取与其关联的属性,然后使用反射来获取属性。

        int GetMaxLength<T>(Expression<Func<T,string>> property);
        

        然后这样称呼它:

        GetMaxLength<Users>((u)=>LastName)
        

        【讨论】:

          【解决方案5】:

          您可以编写一个扩展方法,但它必须接受PropertyInfo 而不是string 的第一个参数(因为string 本身没有属性。)它看起来像这样:

          public static int GetMaxLength(this PropertyInfo prop)
          {
              // TODO: null check on prop
              var attributes = prop.GetCustomeAttributes(typeof(FieldLengthAttribute), false);
              if (attributes != null && attributes.Length > 0)
              {
                  MaxLengthAttribute mla = (MaxLengthAttribute)attributes[0];
                  return mla.MaxLength;
              }
          
              // Either throw or return an indicator that something is wrong
          }
          

          然后通过反射获得属性:

          int maxLength = typeof(Users).GetProperty("LastName").GetMaxLength();
          

          【讨论】: