LINQ 的一大強項,就是 deferred execution。所謂的 deferred execution,是指當下宣告時只是宣告未來要執行的命令,而實際的執行要等到列舉(enumerate) 時才真的開始。
範例
class Program
{
static void Main(string[] args)
{
var stringArray = new string[] { "A", "B", "D", "D", "E"};
//宣告執行的動作,未實際執行
var q = from i in stringArray
where i.StartsWith("D")
select i;
//列舉時才真的執行
var count = q.Count();
Console.WriteLine(count);
}
}
這裡看來沒什麼問題。
問題範例
class Program
{
static void Main(string[] args)
{
var stringArray = new string[] { "A", "B", "D", "D", "E"};
var enumCount = 0;
//宣告執行的動作,未實際執行
var q = from i in stringArray
select new {EnumCount = enumCount++, i};
//列舉時才真的執行
foreach (var item in q)
{
enumCount++;
Console.WriteLine("{0}/{1}", enumCount, item.EnumCount );
}
}
}
輸出
看到問題了嗎?原以為在 q 裡面的值應該是 0, 1, 2, 3, 4,結果輸出的卻是 0, 2, 4, 6, 8。
原因是在實際執行時(foreach loop 內)受到了 enumCount++這一行的干擾,讓原本的執行原意被扭曲了。
建議
LINQ 雖然好用,但在執行時千萬要注意 deferred execution 的現象。不該 deferred execution 時,就直接列舉吧。即 .ToList(), ToArray(), Sum() 等
沒有留言:
張貼留言