【问题标题】:Getting property names of a class using expressions, static methods, and a base object使用表达式、静态方法和基础对象获取类的属性名称
【发布时间】:2013-07-18 11:03:33
【问题描述】:

我有一个常见问题,我正试图以特定方式解决问题。

基本上使用 Winforms,我试图在表单中设置控件的“DisplayMember”和“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 来实现我想要的?我觉得我很接近,但想不出如何改变它。

【问题讨论】:

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


    【解决方案1】:

    您当前的 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】:

    我创建了一个 Helper 类来提取属性名称

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

    【讨论】:

    • 你将如何调用这个方法来获取实际类的属性名称?我已经尝试过你这里的东西,但无法让它工作。
    • 一个简单的调用,如 PropertySupport.ExtractPropertyName(() => YouClassInstance.Property)。我在所有项目中都使用它,它对我来说非常好用。
    • 啊,好吧,这是我从未尝试过的新对象的更新。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      • 1970-01-01
      相关资源
      最近更新 更多