Щойно отримав 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
. Це вже завдання, яким є значення рядка, введеного в консоль. Не потрібно чекати повернення результату; це не додає нової цінності.