2

为了提高 WrapPanel 的性能,我在我的 WP7 应用程序中引入了线程。一个列表中有很长ListItem-objects,一个一个添加到另一个`List。我有以下两个列表:

public List<Item> OriginalItems;
public List<Item> CopyOfItems;

放在BackgroundWorker.DoWork事件处理程序中的逻辑如下:

workerThread.DoWork += new DoWorkEventHandler((object sender, DoWorkEventArgs e) =>
{
    foreach (var item in OriginalItems)
    {
        Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            CopyOfItems.Add(item);
        });

        // I feel sooo sleepy
    }
});

现在,当我用 - 替换我的评论时,这工作得很好,Thread.Sleep(150)但任何更少的东西(偶尔甚至有更大的值)都会使代码连续多次放入同一个元素中。

为什么会这样,如何解决?

4

1 回答 1

5

这是 C# 中的一个已知问题 - 实际上是 C# 5 中修复的问题。当您从foreachlambda 表达式中的循环中捕获循环变量时,您正在捕获一个变量。该变量通过循环更改其值 - 因此,如果您在“原始”迭代完成后执行从 lambda 表达式创建的委托,您将看到来自“当前”迭代的值。

一个简单的解决方法是在循环中声明和初始化迭代变量的副本,并捕获它:

foreach (var item in OriginalItems)
{
    var copy = item;
    Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
        CopyOfItems.Add(copy);
    });

    // I feel sooo sleepy
}

有关这方面的更多详细信息,请参阅 Eric Lippert 的博客文章“关闭被认为有害的循环变量”

顺便说一句,您的真实代码实际上在循环中做任何工作吗?目前尚不清楚您是否真的在使用线程来做任何重要的事情,而不是将 UI 线程工作分成几个块——这可以在没有BackgroundWorker.

于 2012-07-11T07:10:37.767 回答