Pro vývojáře, co alespoň trochu sledují novinky ohledně jazyka C# a .NET Frameworku, není jistě žádnou novinkou, že připravované nové verze těchto produktů C# 5.0 a .NET Framework 4.5 se budou týkat podpory asynchronního programování pomoci klíčových slov async a await. Pro více informací doporučuji sérii článků zde případně například další články zde a zde. Tato podpora se také někdy označuje jako TAP (Task Asynchrony Pattern).
Jak už bylo řečeno, je tato podpora doplněna přímo na úrovni samotného jazyka. O nutnosti rozšířit syntax jazyka C# o nové klíčové slovo await pro volání asynchronní operace tedy asi není moc pochyb. Zajímavé ale je, že u klíčového slova async označující celou asynchronní metodu (*) tomu tak již není. Neobešli by jsme se náhodou i bez něj?
V zásadě obešli, kompilátor by za asynchronní mohl jednoduše považovat každou metodu, ve které použijeme klíčové slovo await. Přesně takto je to přece u iterátorů, tam kompilátor za iterátor považuje metodu, ve které použijeme klíčová slova yield return nebo yield break. Také asi není tajemstvím, že asynchronní metody a iterátory mají co se týče způsobu jejich implementace hodně společného (**). Proč se tedy Microsoft rozhodl doplnit i druhé klíčové slovo async?
Důvody pro zavedení i tohoto druhého klíčového slova uvedu v pořadí své důležitosti. Možná někoho totiž překvapí, že právě ten první je skutečně ten úplně nejzásadnější.
- Označení metody klíčovým slovem async teprve dovoluje použit slovo await jako klíčové slovo. V obyčejné metodě může totiž výraz await označovat například lokální proměnnou. Toto je problém při zavedení téměř jakéhokoliv nového klíčového slova, jedná se totiž o breaking change tj. validní kód předchozí verze jazyka by již v nové verzi nemusel jít zkompilovat. Microsoft v žádném případě nebere breaking change na lehkou váhu, což je také důvod, proč se obecně zavádění nových klíčových slov docela dost brání. Jen pro zajímavost, přesně ze stejného důvodu není u iterátoru zavedeno například pouze klíčové slovo yield, ale celé dvojslovo yield return (dvojslovo má ale zas obecně tu nevýhodu, že nutí uživatele jazyka – vývojáře - více psát). Také si můžete zkusit, že pokud ve Visual Studio 11 Developer Preview napíšete slovo “await” do obyčejné metody, nezmění se jeho barva.
- U asynchronní metody neodpovídá datový typ výrazu uváděný za return návratové hodnotě celé metody. Pokud je metoda deklarována jako async Task<T>, je výraz za return typu T. Pokud je metoda deklarována jako async Task, žádný výraz za return být nemůže. Slovo async v deklaraci metody může pak pomoci upozornit na tuto zvláštnost.
- Asynchronní metody se samozřejmě co do způsobu jejich běhu chovají velmi odlišně od metod obyčejných (synchronních). Z tohoto hlediska zobrazení (ve VS) označení async z deklarace metody může při volání metod s návratovou hodnotou void (top-level asynchronní metody) upozornit na jejich odlišné chování.
Také je dobré si uvědomit, že ačkoliv se klíčové slovo async uvádí v deklaraci metody, není samo osobě její součástí (v metadatech), jen změní způsob překladu těla dané metody. Pokud máme například nějaký event handler deklarovaný jako:
void button_Click(object sender, EventArgs e)
lze z něho doplněním async udělat asynchronní metodu, kterou lze stále volat pomoci delegátu typu EventHandler nebo Action<object, EventArgs>. To je zase jeden argument proti zavedení tohoto klíčového slova.
(*) nebo “asynchronní lambda výraz”, protože pro ty ohledně “asyncu”, platí úplně to samé jako pro obyčejné metody.
(**) Asynchronní metody je nutné stejně jako Iterátory interně reprezentovat jako stavový automat (state machine). V tohoto důvodu jsou všechny současné (pre-C# 5.0) asynchronní frameworky (včetně mého vlastního) právě založené na iterátorech.