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() 等
沒有留言:
張貼留言