2010-01-25 88 views
2

比方说,你有一个通用类,它有一个List<T> Items;Lambda和使用反射来得到的属性名称

现在想这个基本lambda表达式:

var result = Items.FindAll(x => x.Name = "Filip");

这不仅会只要我们知道T的属性,就不会在通用类型的情况下工作。

所以我想使用反射像这样获取的属性:

PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public);

并以某种方式c​​ombind与上述λ-表达式,它会搜索所有类型的公共属性,看看是否它包含“Filip”,此时我不在乎属性名称是否为Name。

这可能吗?

+0

你_always_在编译时知道你的T的确切类型。不过,我想你可能会谈论一个通用函数。 – 2010-01-25 16:05:01

回答

11
var result = Items.FindAll(x => 
    properties.Any(p => p.PropertyType == typeof(string) && 
         p.GetValue(x, null) == "Filip")); 

显然,这是一个简单的,乐观的字符串比较(你可能想使用string.Compare,例如),但是这应该使思想清晰。

编辑

DTB使得在使用表达式目录树一个很好的建议。你可以做到你以后更快的方式是这样的:

public static class PropertyScanner 
{ 
    static Func<TType, bool> CreatePredicate<TType, TValue>(TValue value, IEqualityComparer<TValue> comparer) 
    { 
     var arg = Expression.Parameter(typeof(TType), "arg"); 

     Expression body = null; 

     Expression<Func<TValue, TValue, bool>> compare = (val1, val2) => comparer.Equals(val1, val2); 

     foreach (PropertyInfo property in typeof(TType).GetProperties(BindingFlags.Public)) 
     { 
      if (property.PropertyType == typeof(TValue) || typeof(TValue).IsAssignableFrom(property.PropertyType)) 
      { 
       Expression prop = Expression.Equal(Expression.Invoke(compare, new Expression[] 
             { 
              Expression.Constant(value), 
              Expression.Property(arg, property.Name) 
             }), 
               Expression.Constant(0)); 

       if (body == null) 
       { 
        body = prop; 
       } 
       else 
       { 
        body = Expression.OrElse(body, prop); 
       } 
      } 
     } 

     return Expression.Lambda<Func<TType, bool>>(body, arg).Compile(); 
    } 

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value) 
    { 
     return ScanProperties<TType, TValue>(source, value, EqualityComparer<TValue>.Default); 
    } 

    public static IEnumerable<TType> ScanProperties<TType, TValue>(this IEnumerable<TType> source, TValue value, IEqualityComparer<TValue> comparer) 
    { 
     return source.Where(CreatePredicate<TType, TValue>(value, comparer)); 
    } 
} 

这将允许你做这样的事情:

var result = Items.ScanProperties("Filip").ToList(); 
+0

非常感谢,这正是我正在寻找的。只是一个侧面说明,为了使它更通用一些,如果你想应用自定义比较器,你会怎么做?也就是说,如果它不是您正在寻找的字符串,但您希望您想要比较两个对象,或者对象属性。在这个例子中有没有一种好方法可以做到这一点? – 2010-01-25 19:39:30

+0

这可能不难想象,但既然你给了这么好的帖子,你可能会对此有所想法。再次感谢。 – 2010-01-25 19:40:08

+0

@Filip:'IEqualityComparer '界面非常简单;你的子类'EqualityComparer '(严格地说你可以直接实现接口,但是除非你特别需要,因为基类中有内置的功能,否则不要这样做)并且覆盖/实现'Equals'函数。它需要目标类型的两个参数,并且返回一个布尔值,不管它们是否相等。至于确定这一点的具体逻辑,这完全取决于你。 – 2010-01-25 19:54:32

3

您可以使用表达式树来构建一个lambda导通飞行:

Func<T, bool> CreatePredicate<T>() 
{ 
    var arg = Expression.Parameter(typeof(T), "arg"); 
    var body = Expression.Equal(Expression.Property(arg, "Name"), 
           Expression.Constant("Filip")); 
    return Expression.Lambda<Func<T, bool>>(body, arg).Compile(); 
} 

IEnumerable<T> GetTWhereNameIsFilip<T>(IEnumerable<T> source) 
{ 
    Func<T, bool> predicate = CreatePredicate<T>(); 
    // cache predicate for max performance 

    return source.Where(predicate); 
} 
+0

这个问题表明他想要搜索所有公共财产的价值。 – 2010-01-25 16:05:12

+0

@Adam Robinson:“此时我不在乎产业名称是否是名称 - 可能他以后会在意吗? – dtb 2010-01-25 16:06:09

+0

性能有很大差异吗? – 2010-01-25 16:06:56

相关问题