LINQ之延遲查詢與立即查詢

LINQ全稱是「Language-Integrated Query」。如果你想要使用或學習LINQ,那你必須安裝.NET Framework 3.5以上,才有辦法使用。

在使用LINQ時有一地方需要特別小心,就是LINQ在「反應」的時間點。LINQ本身預設為「延遲查詢」。什麼是延遲查詢?我這樣說好了,我們寫程式,預設是從上到下,從右到左執行,也就是執行一行就有一行的效果,例如:「Dim intStu = New Integer() {...} 」當complier執行到這一行,這一行中的intStu馬上就產生為數值陣列,這樣的執行模式稱「立即執行」。

但延遲查詢剛好相反,也就是說,就算complier已經執行過這一段程式,但在沒有其他程式使用到之前,它不會產生任何效果

以下我們來看實際的例子,Default.asp中Page_Load事件:

'Implicit
Dim intStu = New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

'LINQ,選擇「偶數」
Dim even = From n In intStu Where n Mod 2 = 0 Select n

Response.Write("LINQ 第一次:<br />")
For Each n In even
 Response.Write(n & "<br />")
Next

'改變陣列值
intStu(0) = 200

Response.Write("LINQ 第二次:<br />")
For Each n In even
 Response.Write(n & "<br />")
Next


執行後的結果會如下:

LINQ 第一次:
2
4
6
8
10
LINQ 第二次:
200 '這裡是重點
2
4
6
8
10


請注意第二次中的第一個結果。我們在執行完LINQ後,程式並沒有馬上產生作用,而是等到有人使用時(For Each n In even),才會去執行。所以在我把陣列的值(intStu(0))做改變後,再去執行第二次的For Each語法時,第二次的For Each會去觸發第二次的LINQ查詢,而LINQ再去讀取已經被修改過的陣列,所以造成第二次第一筆值為200

那如果我今天是希望LINQ查詢的結果是固定的,也就是說,不管我事後如何修改陣列值,事後的For Each結果都是一樣的,那你就必須讓LINQ查詢當下要立即執行。立即執行LINQ也很簡單,可以使用ToArray()ToList()方法來強制立即執行。

'LINQ,選擇「偶數」
'使用ToArray或ToList讓LINQ立即執行
'Dim even = (From n In intStu Where n Mod 2 = 0 Select n).ToList
Dim even = (From n In intStu Where n Mod 2 = 0 Select n).ToArray


執行結果,你會看到第一次與第二次完全一模一樣,第二次不再受陣列改變的影響,也就是說,使用使用ToArray或ToList方法後,LINQ語法已經立即產生作用,而第一次與第二次For Each只是將even變數值讀出,而不是去觸發LINQ查詢。

這一點差異是我們在使用LINQ時要小心的地方,不然程式怎麼看都對,邏輯上下右左也查不出所以然,為什麼執行出來的結果永遠不是我們想要的,記得「LINQ預設是延遲執行」。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。