2011-06-15 95 views
108

我在日常生活中寫了相當多的linq,但大多是簡單的語句。我注意到,當使用where子句時,有很多方法可以編寫它們,並且每個方法都有相同的結果,據我所知。例如;正確的Linq where子句

from x in Collection 
    where x.Age == 10 
    where x.Name == "Fido" 
    where x.Fat == true 
    select x; 

看來是等同於本至少就結果而言:

from x in Collection 
    where x.Age == 10 && 
     x.Name == "Fido" && 
     x.Fat == true 
    select x; 

那麼,有沒有真的比其他的語法有區別嗎?如果是這樣,什麼是首選的風格,爲什麼?

+167

你有一個布爾型'Fat'屬性?這很簡單。 – 2011-06-15 15:25:00

+81

@Bala R:嘿,如果你的狗很胖,你的狗很胖。 – 2011-06-15 15:46:22

回答

61

第二個會更有效,因爲它只是一個預測,以評估對收集在作爲第一個,它首先將第一謂詞的所有項目的每個項目和結果(這是在縮小這一點)用於第二個謂詞,依此類推。結果逐步縮小,但仍涉及多次傳球。

另外,鏈接(第一種方法)只有在您對謂詞進行AND操作時纔有效。這樣的東西x.Age == 10 || x.Fat == true不適用於你的第一種方法。

+1

使用此擴展可能會導致鏈OR操作條件:http://www.albahari.com/nutshell/predicatebuilder.aspx – jahu 2014-05-16 12:58:34

10

第一個將被實施:

Collection.Where(x => x.Age == 10) 
      .Where(x => x.Name == "Fido") // applied to the result of the previous 
      .Where(x => x.Fat == true) // applied to the result of the previous 

與之相對更簡單(大概 遠遠快 更快):

// all in one fell swoop 
Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true) 
+4

「遠得多」?我們甚至不知道涉及哪個LINQ實現,因此很難將任何性能影響附加到它上面。 – 2011-06-15 15:15:28

+0

在一般情況下,後者只需要1個循環。供應商可以選擇扁平化第一個例子,但這不是必需的。 – user7116 2011-06-15 15:17:24

+2

確實......但你聲稱後者*的速度要快得多。一點都不明顯,它會顯着更快 - 畢竟,性能差異的重要性取決於如何使用它。 – 2011-06-15 15:19:07

115

編輯:LINQ到對象不行爲我如何預期它。你可能有興趣在我剛剛寫了這個blog post ...


他們在什麼將被稱爲方面具有不同的 - 第一個是等價於:

Collection.Where(x => x.Age == 10) 
      .Where(x => x.Name == "Fido") 
      .Where(x => x.Fat == true) 

wheras後者相當於:

Collection.Where(x => x.Age == 10 && 
         x.Name == "Fido" && 
         x.Fat == true) 

現在什麼區別在於實際上使得取決於實施被調用。如果它是一個基於SQL的提供者,我希望這兩者最終創建相同的SQL。如果它在LINQ to Objects中,那麼第二個將具有更少的間接級別(將只有兩個迭代器而不是四個)。在速度方面,這些間接水平是否爲顯着是另一回事。

通常,如果他們覺得他們代表顯著不同的條件(例如,一個是與對象的一部分來做,一個是完全獨立的)和一個where條款時,各方面條件都密切,我會用幾個where條款(例如,特定值大於最小值且小於最大值)。基本上,在任何輕微的性能差異之前,值得考慮可讀性。

+0

@sixlettervariables:Doh,謝謝。 – 2011-06-15 15:17:57

+1

@JonSkeet也許我錯了,但在對Linq的實現進行快速回顧之後,我不確定這一點。嵌套在哪裏通過靜態方法'CombinePredicates'進行組合。集合僅由具有組合謂詞的單個迭代器迭代一次。當然,將func組合起來會有性能影響,但它非常有限。你還好嗎 ? – Cybermaxs 2013-04-04 11:54:09

+0

@Cyber​​maxs:不知道*什麼*,確切地說?我從來沒有建議這個集合會被迭代多次。 – 2013-04-04 11:57:43

2

從底層看,這兩個語句將被轉換成不同的查詢表示。取決於CollectionQueryProvider,這可能會被優化或不被優化。

當這是一個linq-to-object調用時,多個where子句將導致一系列IEnumerables彼此讀取。使用單語句形式將有助於提高表現。

當底層提供程序將其翻譯爲SQL語句時,兩種變體都會創建相同語句的機會很大。

10

當我運行

from c in Customers 
where c.CustomerID == 1 
where c.CustomerID == 2 
where c.CustomerID == 3 
select c 

from c in Customers 
where c.CustomerID == 1 && 
c.CustomerID == 2 && 
c.CustomerID == 3 
select c customer table in linqpad 

對我的客戶表它輸出相同的SQL查詢

-- Region Parameters 
DECLARE @p0 Int = 1 
DECLARE @p1 Int = 2 
DECLARE @p2 Int = 3 
-- EndRegion 
SELECT [t0].[CustomerID], [t0].[CustomerName] 
FROM [Customers] AS [t0] 
WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = @p1) AND ([t0].[CustomerID] = @p2) 

所以在轉換爲SQL是沒有區別的,你已經在其他答案中看到他們將如何轉換爲lambda表達式

+0

好的,那麼你想說如果我使用其中的任何一個,它就不會有任何性能影響? – 2017-05-27 05:18:12

+0

WHERE子句實際上是鏈接的。所以,你如何寫它並不重要。沒有性能差異。 – hastrb 2017-08-18 10:39:48