2014-01-30 61 views
4

更新2017年3月31日使用ToList()對使用的IList

,因爲這個職位,我已經學到了一些事情,所以想給使用ToList一個重要原因從資源庫返回的IEnumerable返回時從存儲庫 - 調用ToList將(當使用IQueryable時)在數據庫上執行已翻譯的SQL,而不是將記錄拉入內存然後進行過濾。我不相信隱式轉換爲IEnumerable或IList會這樣做。


遵循MSDN網站上的一些教程,我在我的應用程序中使用了通用存儲庫層。該存儲庫層由我的服務層調用,然後由控制器調用。

查看通用存儲庫,數據被提取並通過調用ToList()返回。但是,該方法的返回類型爲IEnumerable,這意味着服務層必須接受IEnumerable,並且在返回控制器之前,它必須再次IEnumerable上調用ToList()

示例 - 庫:

public IEnumerable<TEntity> Get(
    Expression<Func<TEntity, bool>> filter = null, 
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, 
    string includeProperties = "") 
{ 
    IQueryable<TEntity> query = dbSet; 

    if (filter != null) 
    { 
     query = query.Where(filter); 
    } 

    foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) 
    { 
     query = query.Include(includeProperty); 
    } 

    return orderBy != null ? orderBy(query).ToList() : query.ToList(); 
} 

實例 - 服務層

public IList<DOC> SearchDocuments(string docInfo) 
{ 
    // build the predicate and logic, etc 

    // grab all the matching documents with the relationships 
    IEnumerable<DOC> documents = _unitOfWork.DocumentRepository.Get(
     predicate, 
     p => p.OrderBy(d => d.DocInfo), 
     "DocRelationship, DocRelationship.OtherDocTable"); 

    return documents.ToList(); 
} 

從我所做的閱讀,這似乎是最好簡單地呈現給控制器一個List它需要的對象與IEnumerableIQueryable

因此,我認爲不是返回IEnumerable而是返回IList來代替。我在這裏錯過了什麼 - 爲什麼MSDN團隊選擇IEnumerable進行設計並致電ToList?這會有用嗎?在我看來,轉換不止一次是沒有效率和毫無意義的,特別是在處理大量數據時。

我很抱歉提前,如果這不明確或已經有答案,但我一直在尋找和閱讀其他帖子IEnumerable與IQueryable與IList,但我仍然不明白這個問題。

+0

他們是不同類型/接口和實體框架中的語義是不同的(在IQueryable上調用'ToList()'實現了這個查詢,所以如果你對查詢有進一步的改進,它們將在內存中完成,而不是在數據庫中完成)。 – 48klocs

回答

7

返回最小界面,爲您的特定情況工作

通常IEnumerable<T>足夠,並給予更大的靈活性,但如果你看到自己需要使用.ToList()經常(和正當的理由)返回IList<T>甚至List<T>

  • IEnumerable<T>允許更容易懶惰的評價和單元測試(因爲它比IList小 - 所以要儘量堅持下去
  • 您的樣品沒有顯示出正當理由叫.ToList() - 合併IEnumerable<T>直到你知道你正在尋找什麼,甚至可以讓你更好的表現(即如果經過幾次檢查,你決定你只需要一個元素,但ToList會迫使你獲取10000)。
+0

什麼會被認爲是使用'IList'或'List'的有效理由? – Cody

+0

@Cody通常,一種好的方法是在面向公衆的API中使用IList (適當時,需要列表語義),然後在內部列出以實現API。這使您可以更改爲IList 的不同實現,而不會破壞使用您的類的代碼。 –

+1

因此,在我的存儲庫層 - 我應該改爲使用'AsEnumerable'而不是'ToList'來返回'IEnumerable'? – Cody

0

你很好。現在正在發生的主要事情是,repo中的.ToList()實際上是在對數據庫執行查詢。但是將這個列表作爲IEnumerable返回,所有你真正要做的就是裝箱,以便結果是通用的,不可改變的。有一些開銷可以在稍後取消裝箱,但由於存儲庫的職責是返回REQUESTED數據,因此應該像這樣將其返回。

我想這可能是團隊的想法。您要求提供這些數據,所以在這裏。如果您需要對其進行進一步編輯,則必須再次列舉它,以便對該列表進行任何修改。這沒什麼錯。實際上,它支持SoC。

通常情況下,我的回購返回IEnumerable的,那麼,如果我的服務層需要返回類似DTO的視圖模型,我將使用IEnum建立新的對象:

var myEnumerable = _uow.MyJunk.Get(j => j.Stuff.Where(a => a.OtherJunk == something); 
var myDtos = myEnumerable.Select(obj => new DtoClass { Foo = obj.Foo, Bar = obj.Bar }; 
return myDtos; 
+2

你在說什麼「拳擊」?你可能意味着不同的東西,但它讀取,因爲你在某種程度上指拳擊的價值類型... –

+0

我的錯。我真的無法想象用另一個術語來返回一些東西,因爲它是界面。我看到「拳擊」會如何誤導一些人。 – Sinaesthetic