在使用LINQ時有一地方需要特別小心,就是LINQ在「反應」的時間點。LINQ本身預設為「延遲查詢」。什麼是延遲查詢?我這樣說好了,我們寫程式,預設是從上到下,從右到左執行,也就是執行一行就有一行的效果,例如:「
但延遲查詢剛好相反,也就是說,就算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預設是延遲執行」。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。