linq lambda在循环中如何工作?

问题描述:

我试图在我的应用程序中实现任务。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 

我还挺发现在调试问题:所有任务具有相同委托,但我不知道为什么以及如何解决此问题。

这是一个很常见的问题。它涉及“捕获变量”如何工作;短版,你需要这样的:

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

问题是,您在分配代表时捕获循环变量i。如果您在分配之前创建临时副本,则可以避免捕获变量并获取所需的值。

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

这是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