2008-12-02 49 views
25

您是否有一種默認類型,您更傾向於使用LINQ查詢結果進行交易?你ToList()?

默認情況下,LINQ將返回IEnumerable<>IOrderedEnumerable<>。我們發現一個List<>通常對我們更有用,所以在大多數情況下,我們習慣了ToList()的查詢,當然在我們的函數參數和返回值中使用List<>

唯一的例外是LINQ to SQL,其中調用.ToList()會過早枚舉IEnumerable

我們還廣泛使用WCF,其默認收集類型爲System.Array。爲了與我們的其他代碼庫保持一致,我們在VS2008的服務引用設置對話框中始終將其更改爲System.Collections.Generic.List

你是做什麼的?

回答

23

ToList總是立即評估序列 - 不僅僅是在LINQ to SQL中。如果你想要的話,那很好 - 但它並不總是合適的。

就我個人而言,我會盡量避免宣佈您直接返回List<T> - 通常IList<T>更合適,並且允許您稍後更改爲其他實現。當然,有些操作僅在List<T>本身指定......這種決定總是很棘手。

編輯:(我會把它放在註釋中,但它會太笨重。)延遲執行允許你處理太大而不適合內存的數據源。例如,如果您正在處理日誌文件 - 將它們從一種格式轉換爲另一種格式,將它們上傳到數據庫,制定一些統計數據或類似的東西 - 您可能很有可能通過流式處理任意數量的數據,但你真的不要想把所有東西都吸進內存。這可能不是您特定應用程序的關注點,但需要牢記。

+1

同意ToList立即評估。我們的想法是,在LINQtoSQL中,這很可能會對性能產生影響(特別是如果我們將幾個LINQ表達式鏈接在一起),但是當我們在內存中時,任何性能下降都可以忽略不計 - 人類的一致性更高重要。 – 2008-12-02 16:56:30

+3

除了表現之外,還有顯着差異。特別是,如果有關查詢的任何內容(例如源中的數據)發生更改,則延遲執行會給您一個不同的答案。有時候這就是你想要的,有時候不是。 – 2008-12-02 17:08:33

2

這取決於您是否需要修改集合。當我知道沒有人會添加/刪除項目時,我喜歡使用數組。我需要排序/添加/刪除項目時使用列表。但是,通常我會盡可能將其保留爲IEnumerable。

16

我們有相同的場景 - WCF與服務器通信,服務器使用LINQtoSQL。

當從服務器請求對象時,我們使用.ToArray(),因爲客戶端更改列表是「非法的」。 (意思是說,沒有支持「.Add」,「.Remove」等的目的)。

雖然仍然在服務器上,但是,我建議您將其保留爲默認值(不是IEnumerable,而是IQueryable)。這樣,如果您想要根據某些條件進行更多篩選,則需要在SQL端對篩選進行篩選,步驟爲STILL,直至進行評估。

這是非常重要的一點,因爲它意味着取決於你所做的事情,令人難以置信的性能增益或損失。

例:

// This is just an example... imagine this is on the server only. It's the 
// basic method that gets the list of clients. 
private IEnumerable<Client> GetClients() 
{ 
    var result = MyDataContext.Clients; 

    return result.AsEnumerable(); 
} 

// This method here is actually called by the user... 
public Client[] GetClientsForLoggedInUser() 
{ 
    var clients = GetClients().Where(client=> client.Owner == currentUser); 

    return clients.ToArray(); 
} 

你看到發生了什麼呢?「GetClients」方法將強制從數據庫中下載ALL'clients'...然後Where子句將在GetClientsForLoogedInUser方法中進行篩選。

現在,請注意略有變化:

private IQueryable<Client> GetClients() 
{ 
    var result = MyDataContext.Clients; 

    return result.AsQueryable(); 
} 

現在,實際的評價不會發生,直到「.ToArray」叫...和SQL會做的過濾。好多了!

+0

你的觀點非常明確。但大多數人似乎都錯過了。我一直都在看這種非常糟糕的例子。人們不會停下來思考演員在演出時會做什麼。 – 2008-12-04 04:21:56

7

在Linq-to-Objects的情況下,函數返回List<T>不如返回IList<T>,正如THE VENERABLE SKEET指出的那樣。但通常你仍然可以做得比這更好。如果你要返回的東西應該是不可變的,IList是一個不好的選擇,因爲它邀請調用者添加或刪除東西。

例如,有時您有一個方法或屬性返回Linq查詢的結果,或者使用yield return來懶惰地生成一個列表,然後您意識到第一次調用它時會更好,將結果緩存在List<T>中,然後返回緩存的版本。那麼當返回IList可能是一個壞主意時,因爲調用者可能會爲了自己的目的而修改列表,這會破壞緩存,使其更改對所有其他調用者可見。

更好的是返回IEnumerable<T>,所以他們只有前向迭代。如果調用者希望快速隨機訪問,即他們希望他們可以使用[]通過索引訪問,他們可以使用Linq定義的ElementAt,以便它悄悄地嗅探IList並使用它(如果可用),如果不可用,線性查找。

我已經使用ToList的一件事是,當我有一個Linq表達式的混合系統與自定義運算符混合使用yield return來篩選或轉換列表。在調試器中單步執行可能會因爲跳轉執行懶惰評估而變得混亂,所以我有時會臨時將ToList()添加到幾個位置,以便我可以更輕鬆地執行執行路徑。 (雖然如果執行的東西有副作用,這可能會改變程序的含義。)

2

如果您不需要列表<>的附加功能,爲什麼不堅持使用IQueryable <>? !?!?!最常見的分母是最好的解決方案(特別是當你看到蒂莫西的答案時)。