2010-09-26 78 views
2

我試圖在我的應用程序中實現任務。linq lambda在循環中如何工作?

這裏的示例代碼:

有一個簡單的接口I,3類衍生自它(A,B,C) 創建是列表,以A,B,C的實例poplualte它,然後爲對方創建一個任務來調用方法do1();

interface I 
    { 
     void do1(); 

    } 

    class A : I 
    { 
     public void do1() 
     { 
      Console.WriteLine("A"); 
     } 
    } 


    class B : I 
    { 
     public void do1() 
     { 
      Console.WriteLine("B"); 
     } 
    } 


    class C : I 
    { 
     public void do1() 
     { 
      Console.WriteLine("C"); 
     } 
    } 

    class Program 
    { 
     public static void Main(string[] args) 
     { 
      List<I> l = new List<I>(); 
      l.Add(new A()); 
      l.Add(new B()); 
      l.Add(new C()); 


      var TaskPool = new List<Task>(); 


      foreach (var i in l) 
      { 
       Task task = new Task(() => i.do1() 

        ); 
       TaskPool.Add(task); 
      } 


      foreach (var c in TaskPool) 
      { 
       c.Start(); 
      } 

      Thread.Sleep(3000); 
      Console.Read(); 
     } 


    } 

我期待看到

A 
B 
C 

在輸出中,而是它我得到

C 
C 
C 

我還挺發現在調試問題:所有任務具有相同委託,但我不知道爲什麼以及如何解決此問題。

回答

7

這是一個很常見的問題。它涉及「捕獲變量」如何工作;短版,你需要這樣的:

foreach (var i in l) 
{ 
    var copy = i; 
    Task task = new Task(() => copy.do1()); 
    TaskPool.Add(task); 
} 

這裏的問題是,i(從foreach)是技術上宣佈循環的範圍,因而在該範圍拍攝;您每次捕獲相同的變量(C#捕獲變量,而不是*值)。在內部添加copy,循環範圍改變了這個;由於範圍,copy分別被捕獲每次迭代

+0

感謝您的解釋。 「複製」真的是一個副本嗎?據我所知,這只是另一個參考,賴特? – 2010-09-26 10:46:47

+2

@portland:它是'i' *的*值的副本,無論這個值是...無論它是一個引用還是一個值類型值。 – 2010-09-26 11:11:24

5

問題是,您在分配代表時捕獲循環變量i。如果您在分配之前創建臨時副本,則可以避免捕獲變量並獲取所需的值。

foreach (var i in l) 
{ 
    var local = i; 
    Task task = new Task(() => local.do1()); 
    TaskPool.Add(task); 
} 
3

這是linq表達式的預期行爲。這有點被稱爲變量捕獲。有關此主題的一些詳細信息,請參閱this link

就你而言,只需用方法組替換linq表達式即可。我的意思是:這 ...

Task task = new Task(i.do1); 

,而不是這個......

Task task = new Task(() => i.do1()); 

編輯:還有一件非常重要的事情。您已通過添加A,B,C(按特定順序)將項目添加到列表中。這並不能保證A任務將在B任務之前運行,等等。你可以得到任何東西作爲輸出,ABC,ACB等等。

+2

+1不是一個很好的解釋 - 但解決方案是優雅的,它的工作原理:) – 2010-09-26 10:44:50

+0

根據Marc Gravell♦的評論 – 2010-09-26 10:48:04

+1

,我仍然很難看出差異我提供的鏈接有關於該主題的一些很好的信息。我認爲作家以比我更好的方式解釋它。 – Yogesh 2010-09-26 10:49:34