Вызов метода async с С# 5.0
Я делаю некоторые тесты с новым асинхронным шаблоном С# 5.0 (async/await) У меня проблема с пониманием того, как вызываются асинхронные методы.
Учитывая этот код:
private async Task<string> DownloadAsync()
{
progress.ProgressChanged += (s, e) =>
{
progressBar1.Value = e.value;
};
return await DownloadSomething(myurl, progress);
}
private async void CallDownloadAsync()
{
string text = await DownloadAsync();
progressBar1.Value = 0;
label1.Text = "Done!";
}
private void button4_Click(object sender, EventArgs e)
{
CallDownloadAsync();
}
Итак, этот код работает очень хорошо. Когда я нажимаю кнопку "button4", начинается загрузка, и мой ProgressBar обновляется правильно.
Но я хотел бы немного уменьшить свой код, удалив метод CallDownloadAsync() следующим образом:
private void button4_Click(object sender, EventArgs e)
{
new Action(async () =>
{
string result = await Task.Run<string>(() => DownloadAsync());
}).Invoke();
label1.Text = "Running...";
}
Итак, здесь я хочу, чтобы прямо инициировать действие, которое вызывает метод DownloadAsync, но когда я нажимаю на свою Button4, у меня есть операция Неверная операция на основе progressBar. Поэтому я не понимаю, в чем основное отличие между Action() и вызовом моего метода CallDownloadAsync().
Ответы
Ответ 1
Разница в том, что в первом случае вы вызываете CallDownloadAsync()
из потока пользовательского интерфейса (контекст).
В последнем случае DownloadAsync()
вызывается из инициированной задачи, которая обычно выполняется в другом потоке, создаваемом TPL (параллельной библиотекой задач) из потока пользовательского интерфейса или потоков, созданных из него.
В WPF для компонентов пользовательского интерфейса может быть доступен только выделенный поток пользовательского интерфейса или (его дочерние) потоки, созданные из-под него (т.е. с тем же контекстом пользовательского интерфейса).
Ответ 2
Вы можете найти мое async
/await
intro. В частности, метод async
не работает в фоновом потоке; Task.Run
используется для запуска чего-то в фоновом потоке, следовательно, разница в вашем коде.
В общем, вам следует избегать async void
, если вы не пишете обработчик событий async
. Вот так:
private async void button4_Click(object sender, EventArgs e)
{
label1.Text = "Running...";
string result = await DownloadAsync();
progressBar1.Value = 0;
label1.Text = "Done!";
}