TLDR: Нет синхронизации c контекст, означающий, что контекст не проинформирован о начале и завершении операции. Исключения генерируются в потоке пула потоков.
Метод async void
преобразуется компилятором. Возьмите это в качестве примера
public async void Test()
{
}
Результирующий сгенерированный код выглядит примерно так
public void Test()
{
<Test>d__0 stateMachine = new <Test>d__0();
stateMachine.<>4__this = this;
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
Важной частью здесь является AsyncVoidMethodBuilder
struct
. Глядя на функцию Create()
, вы можете увидеть, что она пытается найти текущий SynchronizationContext
, если он есть, затем вызвать virtual
OperationStarted()
. Поскольку для ядра. net нет контекста syn c, это будет пропущено.
Следующая интересная часть этого компоновщика - AwaitUnsafeOnCompleted()
. Эта функция вызывается, когда внутри вашего метода у вас есть await
. Если там возникает исключение, происходит ThrowAsync()
, что вызывает исключение в потоке потоков, поскольку отсутствует контекст syn c.