async void это костыль .NET’а



Многие .NET разработчики знают, что с 5й версии C# в языке появились инструменты для реализации концепции асинхронного программирования.

Ключевые слова async/await, типы данных Task и Task<T>, библиотека TPL.



Однако, мало кто знает почему два слова, async void, можно написать друг за другом, а компилятор не отругается, в отличие от бородатого сеньора-помидора на код ревью.



Казалось бы, всё просто: если метод возвращает что-то типа T, то его асинхронный вариант вернёт Task<T>.

Если не возвращается ничего, то есть стоит void, то асинхронный вариант имеет тип Task.



Однако, при внедрении киллер фичи, разрабам сишарпа было важно не поломать обратную совместимость и консистентность парадигм. Да-да, C# - это мультипарадигмальный язык программирования. И помимо всего прочего там на уровне языка встроена событийная система.



То есть, можно кидать события, создавать обработчики, регистрировать их, реализовать паттерн Publisher-Subscriber и многое другое. Но, для событийно-ориентированного программирования странно, когда обработчик имеет возвращаемый тип.



Поэтому было принято решение сделать такую штуку, с которой мы живём до сих пор. Всё ради существования асинхронной обработки событий на уровне языка.



Почему async void нельзя применять в реализации типовых задач асинхронного программирования?

У него совершенно другая семантика.



1️⃣ Исключения, выброшенные в такой среде не отлавливаются через catch. Они не оборачиваются в задачу, а вызываются прямо на контексте синхронизации. Отследить такое можно только с помощью глобальных «ловцов всего», что есть прямая дорога к неподдерживаемости.



2️⃣ Методы с такой сигнатурой нельзя компоновать с другими асинхронными вызовами через общий API. Цепочки задач, коллбеки при продолжении, общее ожидание - всё это недоступно.



3️⃣ Такой код сложно тестировать и поддерживать. Например, MS Test вовсе работает только с асинхронным кодом, возвращающим Task и Task<T>. Для каждого конкретного случая придётся писать свой собственный контекст синхронизации. Решение не простое и далеко не оптимальное.



Ну а больше деталей - на странице MSDN