微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

foreach标识符和闭包

如何解决foreach标识符和闭包

编辑:在C#5中,所有这些都发生了变化,更改了定义变量的位置(在编译器看来)。从 。

第二个是安全的;第一个不是。

使用foreach,变量在循环 声明-即

Foo f;
while(iterator.MoveNext())
{
     f = iterator.Current;
    // do something with f
}

这意味着f就闭包范围而言只有1 ,并且线程很可能会感到困惑- 在某些实例上多次调用方法,而在其他实例上根本不调用方法。你可以用第二个变量声明,解决这个问题 的内部 循环:

foreach(Foo f in ...) {
    Foo tmp = f;
    // do something with tmp
}

这样,tmp在每个关闭范围中都有一个单独的位置,因此没有发生此问题的风险。

这是问题的简单证明:

    static void Main()
    {
        int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        foreach (int i in data)
        {
            new Thread(() => Console.WriteLine(i)).Start();
        }
        Console.ReadLine();
    }

输出随机):

1
3
4
4
5
7
7
8
9
9

添加一个临时变量,它可以工作:

        foreach (int i in data)
        {
            int j = i;
            new Thread(() => Console.WriteLine(j)).Start();
        }

(每个号码一次,但是当然不能保证顺序)

解决方法

在下面的两个摘要中,第一个是安全的还是第二个必须做?

安全地说,每个线程是否保证从创建线程的同一循环迭代中调用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();
}

更新: 正如Jon Skeet的答案中指出的那样,这与线程无关。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。