Только что получил VS2012 и пытаюсь разобраться async
.
Допустим, у меня есть метод, который получает какое-то значение из источника блокировки. Я не хочу, чтобы вызывающий метод блокировал. Я мог бы написать метод для приема обратного вызова, который вызывается при поступлении значения, но поскольку я использую C # 5, я решил сделать метод асинхронным, чтобы вызывающим абонентам не приходилось иметь дело с обратными вызовами:
// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
Вот пример метода, который его вызывает. Если бы PromptForStringAsync
не асинхронный, этот метод потребовал бы вложения обратного вызова в обратный вызов. С помощью async я могу написать свой метод очень естественным образом:
public static async Task GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
Console.WriteLine("Welcome {0}.", firstname);
string lastname = await PromptForStringAsync("Enter your last name: ");
Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}
Все идет нормально. Проблема в том, когда я вызываю GetNameAsync:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
Все дело в GetNameAsync
том, что он асинхронный. Я не хочу, чтобы он блокировался, потому что я хочу как можно скорее вернуться к MainWorkOfApplicationIDontWantBlocked и позволить GetNameAsync делать свою работу в фоновом режиме. Однако, вызывая его таким образом, я получаю предупреждение компилятора в GetNameAsync
строке:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
Я прекрасно понимаю, что «выполнение текущего метода продолжается до завершения вызова». В этом суть асинхронного кода, верно?
Я предпочитаю, чтобы мой код компилировался без предупреждений, но здесь нечего «исправлять», потому что код выполняет именно то, что я намеревался делать. Я могу избавиться от предупреждения, сохранив возвращаемое значение GetNameAsync
:
public static void DoStuff()
{
var result = GetNameAsync(); // supress warning
MainWorkOfApplicationIDontWantBlocked();
}
Но теперь у меня есть лишний код. Visual Studio, кажется, понимает, что я был вынужден написать этот ненужный код, потому что он подавляет обычное предупреждение «значение никогда не использовалось».
Я также могу избавиться от предупреждения, заключив GetNameAsync в метод, который не является асинхронным:
public static Task GetNameWrapper()
{
return GetNameAsync();
}
Но это еще более лишний код. Поэтому мне приходится писать код, который мне не нужен, или терпеть ненужные предупреждения.
Есть ли что-то неправильное в моем использовании async?
GetNameAsync
предоставить полное имя, которое было предоставлено пользователем (т.е. Task<Name>
вместо того, чтобы просто возвращать Task
?), DoStuff
Можно было бы сохранить эту задачу, и либо await
ее после другого метода, либо даже передать задачу этому другому метод, чтобы он мог await
или Wait
где-то внутри его реализации.
async
ключевое слово.
PromptForStringAsync
вы делаете больше работы, чем вам нужно; просто верните результатTask.Factory.StartNew
. Это уже задача, значение которой - строка, введенная в консоли. Не нужно ждать возврата результата; это не добавляет никакой новой ценности.