猿问

foreach标识符和闭包

在下面的两个片段中,第一个是安全的,还是必须执行第二个?

安全地说,我的意思是每个线程是否保证从创建线程的同一个循环迭代中调用foo上的方法?

或者必须将对新变量“local”的引用复制到循环的每一次迭代中?

var threads = new List<Thread>();foreach (Foo f in ListOfFoo){      
    Thread thread = new Thread(() => f.DoSomething());
    threads.Add(thread);
    thread.Start();}

-

var threads = new List<Thread>();foreach (Foo f in ListOfFoo){      
    Foo f2 = f;
    Thread thread = new Thread(() => f2.DoSomething());
    threads.Add(thread);
    thread.Start();}

最新情况:正如JonSkeet的答案所指出的,这与线程无关。


foreach标识符和闭包

富国沪深
浏览 836回答 3
3回答

慕桂英3389331

这是C#5中的所有更改,并对定义变量的位置进行了更改(在编译器的眼里)。从…C#5以后,它们是相同的.在C#5之前第二个是安全的,第一个是不安全的。带着foreach,变量被声明。外循环-即Foo&nbsp;f;while(iterator.MoveNext()){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f&nbsp;=&nbsp;iterator.Current; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;something&nbsp;with&nbsp;f}这意味着只有一个f就闭包范围而言,线程很可能会感到困惑-在某些实例上多次调用该方法,而对其他实例则完全不调用。您可以通过第二个变量声明来修复这个问题。内循环:foreach(Foo&nbsp;f&nbsp;in&nbsp;...)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;Foo&nbsp;tmp&nbsp;=&nbsp;f; &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;do&nbsp;something&nbsp;with&nbsp;tmp}然后这里有一个单独的tmp在每个关闭范围内,因此不存在此问题的风险。以下是这个问题的一个简单证明:&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;Main() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[]&nbsp;data&nbsp;=&nbsp;{&nbsp;0,&nbsp;1,&nbsp;2,&nbsp;3,&nbsp;4,&nbsp;5,&nbsp;6,&nbsp;7,&nbsp;8,&nbsp;9&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(int&nbsp;i&nbsp;in&nbsp;data) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Thread(()&nbsp;=>&nbsp;Console.WriteLine(i)).Start(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.ReadLine(); &nbsp;&nbsp;&nbsp;&nbsp;}产出(随机):1 3 4 4 5 7 7 8 9 9添加一个临时变量,它可以工作:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(int&nbsp;i&nbsp;in&nbsp;data) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;j&nbsp;=&nbsp;i; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;Thread(()&nbsp;=>&nbsp;Console.WriteLine(j)).Start(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}(每个数字一次,但订单当然不能保证)

胡说叔叔

波普·卡特林和马克·格雷维尔的答案是正确的。我只想添加一个链接到我关于闭包的文章(讨论Java和C#)。只是觉得它可能会增加一点价值。编辑:我认为值得举一个没有线程不可预测性的例子。这里有一个简短但完整的程序,展示了这两种方法。“坏动作”列表打印10次,“好动作”列表从0到9。using&nbsp;System;using&nbsp;System.Collections.Generic;class&nbsp;Test{ &nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;void&nbsp;Main()&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List<Action>&nbsp;badActions&nbsp;=&nbsp;new&nbsp;List<Action>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List<Action>&nbsp;goodActions&nbsp;=&nbsp;new&nbsp;List<Action>(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i=0;&nbsp;i&nbsp;<&nbsp;10;&nbsp;i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;copy&nbsp;=&nbsp;i; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;badActions.Add(()&nbsp;=>&nbsp;Console.WriteLine(i)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goodActions.Add(()&nbsp;=>&nbsp;Console.WriteLine(copy)); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("Bad&nbsp;actions:"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(Action&nbsp;action&nbsp;in&nbsp;badActions) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine("Good&nbsp;actions:"); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(Action&nbsp;action&nbsp;in&nbsp;goodActions) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;}}
随时随地看视频慕课网APP
我要回答