我有以下代码段:
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
的方法调用中设置断点表明正确的参数正通过Task传递给方法。但是,当我的程序实际上归结为WriteProductFile方法时,参数变得不匹配。即,传入了与文件路径不匹配的字符串列表,因此一旦程序完成,我的数据就不好了。没有抛出任何错误,程序执行正常,但错误的信息被写入错误的文件。
我认为ConcurrentDictionary和Lock会处理可能出现的任何线程问题,但显然我错过了一些东西。有什么想法吗?
答案 0 :(得分:3)
您正在捕获循环变量。您必须在循环内声明一个local。
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的帖子:Closing over the loop variable considered harmfuil.