LINQ 的查询执行何时是延迟执行,何时是立即执行,以及查询的复用
延遲執(zhí)行的經典例子:
我們用?select ++i 就可以看到在foreach 時候,查詢才被執(zhí)行。
public static void Linq99()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = from n in numbers select ++i;
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
輸出結果:
v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10
foreach每一個遍歷的時候,select出來的值和當前i的值都是一樣的。
?
立即執(zhí)行的經典例子:
public static void Linq99()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = (from n in numbers select ++i).ToList();
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
執(zhí)行結果:
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
這個例子的代碼跟上面延遲執(zhí)行的例子代碼唯一的差別在于多了一個.ToList();
這也可以證明我們之前提到的原則:
只有到用的時候才會去執(zhí)行查詢
由于 .ToList(); 的存在,在這里就要用到了,所以在這里就執(zhí)行了查詢,而不是在foreach中執(zhí)行查詢。注意,這時候出來的結果是一個數組了.參看后面的幾個例子.
執(zhí)行的一個特殊情況:重復執(zhí)行
請看下面例子:
查詢出一個int數組中小于3的數字。
下面例子中在第一次查詢后,對數據源作了修改,然后再作第二次查詢,我們可以看到第二次我們不需要再作
lowNumbers = from n in numbers where n <= 3 select n; 這樣的定義,而是直接使用??? foreach (int n in lowNumbers)。另外這兩次的返回結果是不同的,因為我們
在第一次查詢后,對數據源作了修改。
public static void Linq101()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? var lowNumbers = from n in numbers where n <= 3 select n;
??? Console.WriteLine(“First run numbers <= 3:”);
??? foreach (int n in lowNumbers)
??????? Console.WriteLine(n);
??? for (int i = 0; i < 10; i++)
??????? numbers[i] = -numbers[i];
??? Console.WriteLine(“Second run numbers <= 3:”);
??? foreach (int n in lowNumbers)
??????? Console.WriteLine(n);
}
輸出結果:
First run numbers <= 3:
1
3
2
0
Second run numbers <= 3:
-5
-4
-1
-3
-9
-8
-6
-7
-2
0
以上三個例子均來自 101 LINQ Samples
?
下面我們再來看幾個例子,加深對查詢執(zhí)行的理解:
重復查詢的再一個例子:
public static void Linq102()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = from n in numbers select ++i;
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
執(zhí)行結果:
v = 1, i = 1
v = 2, i = 2
v = 3, i = 3
v = 4, i = 4
v = 5, i = 5
v = 6, i = 6
v = 7, i = 7
v = 8, i = 8
v = 9, i = 9
v = 10, i = 10
v = 11, i = 11
v = 12, i = 12
v = 13, i = 13
v = 14, i = 14
v = 15, i = 15
v = 16, i = 16
v = 17, i = 17
v = 18, i = 18
v = 19, i = 19
v = 20, i = 20
?
只執(zhí)行一次的立即查詢:
public static void Linq102()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = (from n in numbers select ++i).ToList();
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
執(zhí)行結果:
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
v = 1, i = 10
v = 2, i = 10
v = 3, i = 10
v = 4, i = 10
v = 5, i = 10
v = 6, i = 10
v = 7, i = 10
v = 8, i = 10
v = 9, i = 10
v = 10, i = 10
那些函數會導致立即執(zhí)行查詢:
以下幾個擴展函數會導致LINQ會立即執(zhí)行。并且只執(zhí)行一次。
.ToArray();
.ToList();
.ToDictionary(k => k);
比如:
public static void Linq102()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = (from n in numbers select ++i).ToDictionary(k => k);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
輸出結果就是:
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
?
小結:
Q:通過上面幾個例子,我們該如何理解LINQ的查詢何時執(zhí)行呢?
A:LINQ的查詢執(zhí)行遵循以下原則:
1、一般情況下(除了下面第三條說的情況),LINQ都是延遲執(zhí)行,原因:以DLINQ為例,越晚被執(zhí)行,對業(yè)務邏輯的理解就越清晰,DLINQ查詢對數據庫的請求壓力越小。編譯器對LINQ查詢優(yōu)化可作的事情越多。
2、由于是延遲執(zhí)行,也就是調用的時候才去執(zhí)行。這樣調用一次就被執(zhí)行一次,這樣就具備了重復執(zhí)行的功能,參看之前的幾個重復執(zhí)行的例子。而這個重復執(zhí)行是不需要再此書寫一邊查詢語句的。
3、如果查詢中我們對查詢結果使用了 ToArray、ToList、ToDictionary 這些轉換成集合的擴展方法。使用這時候出來的對象是一個獨立的集合數組,而不是LINQ查詢,所以這時候不會出現多次查詢,而只是一次查詢。
即:var q = from n in numbers select ++i ;? 這樣一條語句我們可以認為它記錄的不是等號右邊的結果,而是記錄的等號右邊的表達式。
而??? var q = (from n in numbers select ++i).ToDictionary(k => k); 這樣一條語句我們記錄的是等號右邊的計算結果,而不是表達式。
為理解上面說明,我們可以再看兩個例子:
public static void Linq102()
{
??? int[] numbers = new int[] { 5,
4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = from n in numbers select ++i;
??? var qq = q.ToDictionary(k => k);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
??? foreach (var v in q)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
輸出結果:
v = 11, i = 11
v = 12, i = 12
v = 13, i = 13
v = 14, i = 14
v = 15, i = 15
v = 16, i = 16
v = 17, i = 17
v = 18, i = 18
v = 19, i = 19
v = 20, i = 20
v = 21, i = 21
v = 22, i = 22
v = 23, i = 23
v = 24, i = 24
v = 25, i = 25
v = 26, i = 26
v = 27, i = 27
v = 28, i = 28
v = 29, i = 29
v = 30, i = 30
而
public static void Linq102()
{
??? int[] numbers = new int[] { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
??? int i = 0;
??? var q = from n in numbers select ++i;
??? var qq = q.ToDictionary(k => k);
??? foreach (var v in qq)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
??? foreach (var v in qq)
??????? Console.WriteLine(“v = {0}, i = {1}”, v, i);
}
輸出結果為:
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
v = [1, 1], i = 10
v = [2, 2], i = 10
v = [3, 3], i = 10
v = [4, 4], i = 10
v = [5, 5], i = 10
v = [6, 6], i = 10
v = [7, 7], i = 10
v = [8, 8], i = 10
v = [9, 9], i = 10
v = [10, 10], i = 10
?
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的LINQ 的查询执行何时是延迟执行,何时是立即执行,以及查询的复用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win2008下的无线网卡设置
- 下一篇: PL\SQL 打开时出现动态执行表不可访