在迭代之前等待任务完成

时间:2012-11-24 22:42:51

标签: c# .net-4.0 foreach sqlbulkcopy

我有一个函数从目录中读取每个文件并将其上传到数据库。 我无法弄清楚如何在它返回到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“)!; 部分。

感谢。

1 个答案:

答案 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);
}