1

我正在尝试使用字典中的值的副本在每个循环中生成线程。

我最初的理解是,这foreach将创建一个新的范围,并导致:

Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } };
foreach (KeyValuePair<string, string> record in Dict) {
    new System.Threading.Timer(_ =>
    {
        Console.WriteLine(record.Value);
    }, null, TimeSpan.Zero, new TimeSpan(0, 0, 5));
}

哪个写

1
2
2
2

而不是(预期):

1
2
1
2

所以我尝试在foreach中克隆kvp:

KeyValuePair<string, string> tmp = new KeyValuePair<string, string>(record.Key, record.Value);

但这会产生相同的结果。

我也试过了,System.Parallel.ForEach但这似乎需要不是动态的值,这对我的字典来说有点像火车粉碎。

如何使用线程遍历我的字典?

4

1 回答 1

7

问题是关闭你的 lambda,修复的方法是在 for 循环中添加一个局部变量

Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } };
foreach (KeyValuePair<string, string> record in Dict) {

    var localRecord = record;
    new System.Threading.Timer(_ =>
    {
        Console.WriteLine(localRecord.Value);
    }, null, TimeSpan.Zero, new TimeSpan(0, 0, 5));
}

您的版本中发生的是它捕获变量record而不是变量记录的值。因此,当计时器第二次运行时,它使用record数组中第二个元素的“当前值”。

在幕后,这就是您的代码版本中正在发生的事情。

public void MainFunc()
{
    Dictionary<string, string> Dict = new Dictionary<string, string>() { { "sr1", "1" }, { "sr2", "2" } };
    foreach (KeyValuePair<string, string> record in Dict) {

        _recordStored = record;
        new System.Threading.Timer(AnnonFunc, null, TimeSpan.Zero, new TimeSpan(0, 0, 5));
    }
}

private KeyValuePair<string, string> _recordStored;

private void AnnonFunc()
{
    Console.WriteLine(_recordStored.Value);
}

看看你的函数在第一次迭代中运行它时如何具有正确的版本_recordStored,但在_recordStored被覆盖后它只会显示最后一个设置值。通过创建局部变量,它不会进行覆盖。

一种想象的方式(我不确定如何在代码示例中表示它)是它创建_recordStored1第一个循环、_recordStored2第二个循环等等。该函数在调用该函数时使用正确版本的_recordStored#for。

于 2013-07-15T15:41:58.837 回答