2016-12-07 109 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

我有這個收藏家族的問題,我看到他們都類似:\ –