2016-12-07 107 views
-1

我开始为乐趣这种扩展方法,但现在我发现自己陷了进去,如何在扩展方法中使用泛型类成员?

其实我想创建一个扩展方法来扩展LINQ,该方法将是这样的:

books.In(b => b.Id, 1,2,3,4,5); 

它将返回书籍ID范围在第二params[]

它也可以做这样的:

books.In(b => b.Title, "t1","t2","t3","t4","t5"); 

我想出的是这种方法(我今天知道表达式树!):

public static List<TEntity> In<TEntity, TMember>(this List<TEntity> list, 
      Expression<Func<TEntity, TMember>> identifier, params TMember[] keys) 
     { 
      Type t = typeof(TEntity); //How to use reflection here? 

      List<TEntity> myList = list.Where(m => keys.Contains(m.)); 
      return myList; 
     } 

我的问题是如何访问泛型类的成员:从identifier表达即m.Idm.Title? 我可以使用反射来实现这种情况吗?

+4

如果您想使用Enumerable.Where来过滤,'identifier'应该是'Func '。然后它就是'list.Where(m => keys.contains(identifier(m))''尽管您可能想要为键创建一个集合以使查找效率更高。 – Lee

+2

如果意图将其转换为SQL,那么你应该使用'IQueryable'而不是'List'。 – juharr

回答

2

这应该这样做:

public static IEnumerable<TEnitity> In<TEnitity, TMember>(
    this IEnumerable<TEnitity> source, 
    Func<TEnitity, TMember> projector, IEnumerable<TMember> validCases) 
{ 
    var validSet = new HashSet<TMember>(validCases); 
    return source.Where(s => validSet.Contains(projector(s))); 
} 

或者,遵守exaclty与您所建议的签名:

public static IEnumerable<TEntity> In<TEntity, TMember>(
    this IEnumerable<TEntity> source, 
    Func<TEntity, TMember> projector, params TMember[] validCases) 
{ 
    var validSet = new HashSet<TMember>(validCases); 
    return source.Where(s => validSet.Contains(projector(s))); 
} 

为什么我要回IEnumerable<T>而不是List<T>的理由是便宜的推广;如果消费者想要一个返回的列表,那么他只需要拨打ToList,但为什么如果他只想通过枚举遍历一次,他为什么要付出昂贵的枚举费用呢?记住,LINQ是懒惰,利用它并​​使其工作尽可能少。

关于为什么我接受IEnumerable<T>作为论据,再次便宜泛化;为什么只接受一个列表?为什么不是数组,队列,堆栈,集合,迭代器块,哈希集等?

+0

因为这是一个答案,请你解释一下你的代码,为什么'IEnumerable'比'List'好 –

+0

@MohamedAhmed因为'Where'只是返回'IEnumerable ',而不是'List '。此外:你真的想返回一个列表,你可以添加/删除项目吗? – HimBromBeere

+0

我有这个收藏家族的问题,我看到他们都类似:\ –