Właśnie dostałem VS2012 i próbuję sobie poradzić async
.
Powiedzmy, że mam metodę, która pobiera pewną wartość z blokującego źródła. Nie chcę, aby obiekt wywołujący metodę był blokowany. Mógłbym napisać metodę, która odbiera wywołanie zwrotne, które jest wywoływane, gdy nadejdzie wartość, ale ponieważ używam C # 5, decyduję się na asynchronizację metody, aby wywołujący nie musieli zajmować się wywołaniami zwrotnymi:
// 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();
});
}
Oto przykładowa metoda, która to wywołuje. Gdyby PromptForStringAsync
nie była asynchroniczna, ta metoda wymagałaby zagnieżdżenia wywołania zwrotnego w wywołaniu zwrotnym. Dzięki async mogę napisać swoją metodę w bardzo naturalny sposób:
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);
}
Na razie w porządku. Problemem jest to, kiedy zadzwonić GetNameAsync:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
Chodzi o GetNameAsync
to, że jest asynchroniczny. Nie chcę , aby było blokowane, ponieważ chcę wrócić do MainWorkOfApplicationIDontWantBlocked ASAP i pozwolić GetNameAsync robić swoje w tle. Jednak nazwanie tego w ten sposób daje mi ostrzeżenie kompilatora w GetNameAsync
wierszu:
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.
Doskonale zdaję sobie sprawę, że „wykonywanie aktualnej metody jest kontynuowane przed zakończeniem wywołania”. To jest punkt kodu asynchronicznego, prawda?
Wolę, aby mój kod kompilował się bez ostrzeżeń, ale nie ma tu nic do „naprawienia”, ponieważ kod robi dokładnie to, co zamierzam. Mogę pozbyć się ostrzeżenia, przechowując zwracaną wartość GetNameAsync
:
public static void DoStuff()
{
var result = GetNameAsync(); // supress warning
MainWorkOfApplicationIDontWantBlocked();
}
Ale teraz mam zbędny kod. Visual Studio wydaje się rozumieć, że byłem zmuszony napisać ten niepotrzebny kod, ponieważ pomija on normalne ostrzeżenie „wartość nigdy nie używana”.
Mogę również pozbyć się ostrzeżenia, opakowując GetNameAsync w metodę, która nie jest asynchroniczna:
public static Task GetNameWrapper()
{
return GetNameAsync();
}
Ale to jeszcze bardziej zbędny kod. Muszę więc pisać kod, którego nie potrzebuję ani nie toleruję niepotrzebnego ostrzeżenia.
Czy jest coś złego w używaniu async?
PromptForStringAsync
wykonujesz więcej pracy, niż potrzebujesz; po prostu zwróć wynikTask.Factory.StartNew
. Jest to już zadanie, którego wartością jest ciąg wprowadzony w konsoli. Nie ma potrzeby czekać, aż zwróci wynik; takie postępowanie nie dodaje nowej wartości.