C# 任务,等等,没有我想象的那样工作

C# 任务,等等,没有我想象的那样工作,c#,multithreading,task,C#,Multithreading,Task,我正在尝试下载一个文件,等待该文件完成下载,然后读取该文件。我有以下方法来实现这一点: private async Task startDownload(string link, string savePath) { WebClient client = new WebClient(); client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_Do

我正在尝试下载一个文件,等待该文件完成下载,然后读取该文件。我有以下方法来实现这一点:

private async Task startDownload(string link, string savePath)
{      
        WebClient client = new WebClient();
        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
        client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
        await client.DownloadFileTaskAsync(new Uri(link), savePath);              
}

private void checkUpdateButton_Click(object sender, EventArgs e)
{           
    Task task = Task.Factory.StartNew(() => startDownload(versionLink, versionSaveTo));
    task.Wait();

    if (task.IsCompleted)
    {
        checkVersion();
    }
}

checkVersion()
方法读取下载的文件。这会抛出一个
IOException
,表示该文件正被其他文件使用,无法读取。我认为使用
task.Wait
会阻止方法的其余部分在任务完成之前执行?

函数startDownload已经是异步的,因此它将启动任务并立即返回。在调用checkVersion()之前,可以使用ContinueWith确保任务已完成

正如Servy指出的,另一种选择是在Click事件中使用async/await

    private async void checkUpdateButton_Click(object sender, EventArgs e)
    {
        await startDownload(versionLink, versionSaveTo);
        checkVersion();
    }

您需要等待
Task.Factory.StartNew(…)
调用,这样它就不会阻塞UI线程

private async void button1_Click(object sender, EventArgs e)
{
    Task task = await Task.Factory.StartNew(() => startDownload("http://www.zwaldtransport.com/images/placeholders/placeholder1.jpg", "" + "sd.jpg"));
}

private async Task startDownload(string link, string savePath)
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged += Client_DownloadProgressChanged;
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);
}

private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
            checkVersion();
    Console.WriteLine("Done, unless error or cancelled.");
}

private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("Progress changed.");
}

图像占位符由Google Images和其他一些网站提供。

任务。等待将阻止当前线程(在本例中为UI线程),并等待任务完成。在本例中,任务正在完成,但出现错误,因此
task.Wait
将抛出包装在
aggregateeexception
中的错误

正如其他人所指出的,您应该使用
Wait
而不是
Wait
。而且,
DownloadFileCompleted
没有意义,因为您使用的是
downloadfiletasksync
(而不是
DownloadFileAsync
);由于下载是异步的,因此不需要启动新的
StartNew

哦,让我们来处理
WebClient
,并确保我们的命名约定遵循以下规则


两件事:在
StartDownload
中不需要等待,只需返回
client.DownloadFileTaskAsync(新Uri(链接),savePath)
您不需要在UI线程中等待任务。您需要等待它。@user,请查看下面我的答案。我已经对它进行了测试,它工作正常,不会阻塞UI线程。如果您有问题,请发表评论:)这当然会阻止UI线程,冻结应用程序。根据您的第一个建议,我是否要更改startDownload中的任何内容?它仍然会立即返回,因为任务是异步的,所以它仍然会在下载文件时尝试打开该文件。@user2357446它确实会立即返回,但在下载文件之前它不会执行代码,使用此代码。@user2357446您可以删除DownloadFileCompleted的事件处理程序。这与OP的问题相同,因为您在完成启动任务时执行代码,而不是在启动的任务完成时。OP应该在DownloadFileCompleted事件中放置
checkVersion()
,如果那是OP想要的。我一定是误解了。这是一个选择,是的。但不是最好的。
private async void button1_Click(object sender, EventArgs e)
{
    Task task = await Task.Factory.StartNew(() => startDownload("http://www.zwaldtransport.com/images/placeholders/placeholder1.jpg", "" + "sd.jpg"));
}

private async Task startDownload(string link, string savePath)
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged += Client_DownloadProgressChanged;
    client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);
}

private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
            checkVersion();
    Console.WriteLine("Done, unless error or cancelled.");
}

private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("Progress changed.");
}
private async Task startDownloadAsync(string link, string savePath)
{      
  using (var client = new WebClient())
  {
    client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    await client.DownloadFileTaskAsync(new Uri(link), savePath);              
  }
}

private async void checkUpdateButton_Click(object sender, EventArgs e)
{           
  await startDownloadAsync(versionLink, versionSaveTo);
  checkVersion();
}