我有一个函数从目录中读取每个文件并将其上传到数据库。 我无法弄清楚如何在它返回到foreach循环之前等待任务完成,因为它似乎是直接执行,因为任务需要几秒钟:
foreach (string file in Directory.EnumerateFiles(folderPath, "*.xml"))
{
//load file
currentReader = new XmlDataReader(transferInstructions, file);
currentReader.RowsUploaded += new EventHandler<RowsUploadedEventArgs>(currentReader_RowsUploaded);
currentReader.TableUploaded += new EventHandler<TableUploadedEventArgs>(currentReader_TableUploaded);
currentTask = new Task(() => currentReader.executeBulkCopy(initialConnString, workingDatabase));
currentTask.ContinueWith(task =>
{
cleanUp(task);
//MessageBox.Show("Complete!");
});
currentTask.Start();
writeResult("Started the transfer process.");
cmdDataTransfer.Text = "CANCEL TRANSFER";
cmdDataTransfer.ForeColor = Color.DarkRed;
transferAction = () => cancelCurrentReader();
}
我需要等待MessageBox.show继续foreach循环之前的位置。 它需要几秒钟才能到达 清理(任务); //MessageBox.Show("Complete“)!; 部分。
感谢。
答案 0 :(得分:4)
C#5 / .NET 4.5中的async-awqait模式非常适合这种情况。我看到你已经将它标记为.NET4,但是如果你可以使用Async Targeting Pack,那么有一种非常优雅的方式:
void Main()
{
foreach (string file in Directory.EnumerateFiles(folderPath, "*.xml"))
{
currentReader = new XmlDataReader(transferInstructions, file); //load file
currentReader.RowsUploaded += new EventHandler<RowsUploadedEventArgs>(currentReader_RowsUploaded);
currentReader.TableUploaded += new EventHandler<TableUploadedEventArgs>(currentReader_TableUploaded);
var task = Task.Factory.StartNew(() => currentReader.executeBulkCopy(initialConnString, workingDatabase));
await task;
cleanUp(task);
MessageBox.Show("Complete!");
writeResult("Started the transfer process.");
cmdDataTransfer.Text = "CANCEL TRANSFER";
cmdDataTransfer.ForeColor = Color.DarkRed;
transferAction = () => cancelCurrentReader();
}
}
如果你必须保留它VS2010,你将不得不模仿async-await的作用,类似于:
void MyForm()
{
_syncContext = SynchronizationContext.Current;
Execute(Directory.EnumerateFiles(folderPath, "*.xml").GetEnumerator());
}
void Execute(IEnumerator<string> files)
{
if (!files.MoveNext())
{
files.Dispose();
return;
}
Task.Factory.StartNew(() => Execute(files.Current)).ContinueWith(() => Execute(files));
}
public void Execute(string file)
{
currentReader = new XmlDataReader(transferInstructions, file); //load file
currentReader.RowsUploaded += new EventHandler<RowsUploadedEventArgs>(currentReader_RowsUploaded);
currentReader.TableUploaded += new EventHandler<TableUploadedEventArgs>(currentReader_TableUploaded);
() => currentReader.executeBulkCopy(initialConnString, workingDatabase);
cleanUp(task);
_syncContext.Send(updateGUI);
transferAction = () => cancelCurrentReader();
}
public void updateGUI()
{
MessageBox.Show("Complete!");
writeResult("Started the transfer process.");
cmdDataTransfer.Text = "CANCEL TRANSFER";
cmdDataTransfer.ForeColor = Color.DarkRed;
}
编辑现在,我想到它还有一个更简单的方法。您可以将整个循环运行在自己的任务中(委托GUI工作的同步上下文)。使用上面代码的约定:
Task.Factory.StartNew(() =>
{
foreach (var file in Directory.EnumerateFiles(folderPath, "*.xml"))
Execute(file);
}