2

我有以下代码片段:

lock (lockObject) 
{
  foreach (KeyValuePair<string, List<string>> entry in productDictionary) 
  {
    string writePath = String.Format(@"{0}\{1}-{2}.txt", directoryPath, hour,entry.Key);
    Task writeFileTask = Task.Factory.StartNew(() => WriteProductFile(writePath, entry.Value));
  }
}

productDictionary 是我试图迭代的ConcurrentDictionary一个。<string, List<string>>对于每个键值对,我尝试基于 构造一个文件路径Key,然后写出存储在Value. 为此,我启动了一个调用以下方法的新任务:

public static void WriteProductFile(string filePath, List<string> productQuotes)
{
    using(StreamWriter streamWriter = new StreamWriter(filePath)) 
    {
        productQuotes.ForEach(x => streamWriter.WriteLine(x));
    }
}

单步执行代码一开始看起来一切都很好。在方法调用处设置断点WriteProductFile表明正确的参数正在通过任务传递到方法中。但是,当我的程序实际上将其归结为 WriteProductFile 方法时,参数已变得不匹配。即,已传入与文件路径不匹配的字符串列表,因此一旦程序完成,我的数据就不好了。没有抛出错误并且程序执行良好,但错误的信息被写入错误的文件。

我认为 ConcurrentDictionary 和 Lock 会处理可能出现的任何线程问题,但显然我错过了一些东西。有任何想法吗?

4

1 回答 1

3

您正在捕获一个循环变量。您必须在循环内声明一个本地。

foreach (KeyValuePair<string, List<string>> entry in productDictionary) 
{
  string writePath = String.Format(@"{0}\{1}-{2}.txt", directoryPath, hour, entry.Key);
  List<string> list = entry.Value; // must add this.
  Task writeFileTask = Task.Factory.StartNew(() => WriteProductFile(writePath, list));
}

在 C# 5 之前,单个循环变量用于循环的所有迭代。每个闭包都引用相同的变量,因此当循环的新循环开始时会更新该值。要获得明确的解释,您应该阅读 Eric Lippert 的帖子:关闭循环变量被认为是有害的。

于 2012-11-14T17:01:36.987 回答