Щойно отримав 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не було асинхронізації, для цього методу потрібно буде вкладати зворотний дзвінок у зворотній зв'язок. За допомогою асинхроніки я можу написати свій метод таким природним чином:
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 ASAP і дозволити 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();
}
Але це ще більш зайвий код. Тож я мушу писати код, який мені не потрібен або терплять зайве попередження.
Чи є щось про моє використання асинхрони, що тут не так?
GetNameAsyncповне ім’я, яке було надано користувачем (тобто Task<Name>, а не просто повертати Task??), DoStuffМоже потім зберігати це завдання, або awaitвоно після іншого методу, або навіть передавати завдання тому іншому метод, щоб він міг awaitчи Waitце десь усередині його реалізації
asyncключове слово.
PromptForStringAsyncви робите більше роботи, ніж потрібно; просто повернути результатTask.Factory.StartNew. Це вже завдання, яким є значення рядка, введеного в консоль. Не потрібно чекати повернення результату; це не додає нової цінності.