2011年5月26日 星期四

LINQ 的延遲執行(Deferred execution) 造成的奇特現象

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 );
  }
}
}

輸出

image

看到問題了嗎?原以為在 q 裡面的值應該是 0, 1, 2, 3, 4,結果輸出的卻是 0, 2, 4, 6, 8。

原因是在實際執行時(foreach loop 內)受到了 enumCount++這一行的干擾,讓原本的執行原意被扭曲了。

建議

LINQ 雖然好用,但在執行時千萬要注意 deferred execution 的現象。不該 deferred execution 時,就直接列舉吧。即 .ToList(), ToArray(), Sum() 等

沒有留言:

Share with Facebook