使用表达式,静态方法和基础对象获取类的属性名称

时间:2013-07-18 11:03:33

标签: c# .net linq c#-4.0

我有一个共同的问题,我正试图以特定的方式绕过。

基本上使用Winforms,我试图设置" DisplayMember"和#34; ValueMember"表格中的控件。你通常会这样设置:

this.testCombobox.DisplayMember = "PropertyOne";
this.testCombobox.ValueMember = "PropertyTwo";

我想按如下方式重写:

this.testCombobox.DisplayMember = ClassOne.GetPropertyName(c => c.PropertyOne);
this.testCombobox.ValueMember = ClassOne.GetPropertyName(c => c.PropertyTwo);

(注意:2方法调用需要是静态的,以保存创建对象)

我尝试这样做的所有类都继承自基类" BaseObject",所以我按如下方式添加了一个方法:

public static string GetPropertyName<T, P>(Expression<Func<T, P>> action) where T : class
{
    MemberExpression expression = action.Body as MemberExpression;
    return expression.Member.Name;
}

但是,为了使用它,我需要编写以下代码:

this.testCombobox.DisplayMember = BaseObject.GetPropertyName((ClassOne c) => c.PropertyOne);

我的问题是,如何重写方法BaseObject.GetPropertyName以实现我想要的目标?我觉得我很亲密,但想不出怎么改变它。

3 个答案:

答案 0 :(得分:4)

我创建了一个Helper类来提取Proprty Name

  public static class PropertySupport
  {       
    public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
    {
      if (propertyExpression == null)
      {
        throw new ArgumentNullException("propertyExpression");
      }

      var memberExpression = propertyExpression.Body as MemberExpression;
      if (memberExpression == null)
      {
        throw new ArgumentException("Invalide Expression", "propertyExpression");
      }             
      return memberExpression.Member.Name;
    }
  }

你可以按照以下方式使用它:

PropertySupport.ExtractPropertyName(() => DateTime.Now)

它将返回“现在”

修改

这是一个测试控制台应用程序:

  public static class PropertySupport
  {       
    public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
    {
      if (propertyExpression == null)
      {
        throw new ArgumentNullException("propertyExpression");
      }

      var memberExpression = propertyExpression.Body as MemberExpression;
      if (memberExpression == null)
      {
        throw new ArgumentException("", "propertyExpression");
      }      
      return memberExpression.Member.Name;
    }
  }
  public class MyClass
  {
    public MyClass PropertyOne { get; set; }
  }
  class Program
  {    
    static void Main(string[] args)
    {      
      Console.WriteLine(PropertySupport.ExtractPropertyName(() => new MyClass().PropertyOne));
      Console.ReadKey();
    }   
  }

答案 1 :(得分:4)

您当前的GetPropertyName方法将打开泛型T.因此,编译器无法解析它的编译时间,因为您在使用该方法时未指定它。

但是,如果你使你的基类通用,并且在派生类中指定T,并且指定使用派生类的方法(而不是基类),那么它就可以工作。

像这样:

public class BaseClass<T> {
    public static string GetPropertyName<P>(Expression<Func<T, P>> action) {
        MemberExpression expression = action.Body as MemberExpression;
        return expression.Member.Name;
    }
}

public class ClassOne : BaseClass<ClassOne> {
    public string PropertyOne { get; set; }
}
public static class Test {
    public static void test() {
        var displayMember = ClassOne.GetPropertyName(x => x.PropertyOne);
    }
}

答案 2 :(得分:0)

我会在通用助手中建议以下内容:

    public static class GenericHelper<TEntity> {

        public static string GetPropertyName<TProperty>(Expression<Func<TEntity, TProperty>> propertyExpression) {

            return propertyExpression.GetPropertyName();
        }
    }

以及常见用法扩展中的以下内容:

public static class ReflectionExtensions {

    public static PropertyInfo GetProperty<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {

        //TODO: check TEntity, if needed. Now it's ignored

        var member = source.Body as MemberExpression;

        if (member == null) {
            throw new ArgumentException(String.Format(
                "Expression '{0}' refers to a method, not a property.", source));
        }

        var propertyInfo = member.Member as PropertyInfo;

        if (propertyInfo == null) {
            throw new ArgumentException(string.Format(
                "Expression '{0}' refers to a field, not a property.", source));
        }

        return propertyInfo;
    }

    public static string GetPropertyName<TEntity, TProperty>(this Expression<Func<TEntity, TProperty>> source) {

        return source.GetProperty().Name;
    }
}