Использование async void в C#

Использование async void в C# считается плохой практикой, так как оно ведет к проблемам с обработкой ошибок, управлением жизненным циклом задач и тестированием.

Отсутствие возможности обработки исключений

Методы, возвращающие Task или Task<T>, позволяют отлавливать исключения с помощью try-catch. Однако async void не предоставляет такой возможности.

public async void FaultyMethod()
{
    throw new Exception("Ошибка выполнения");
}

Любое исключение в async void методе приведет к завершению процесса, так как оно не может быть перехвачено вызывающим кодом.

Потеря контроля над выполнением задачи

Методы, возвращающие Task, позволяют контролировать их выполнение. async void не дает возможности ожидания завершения метода.

public async void SomeMethod()
{
    await Task.Delay(1000);
    Console.WriteLine("Завершено");
}

public async Task CallMethod()
{
    SomeMethod();
    Console.WriteLine("Этот код выполнится раньше");
    await Task.Delay(2000);
}

В данном случае CallMethod продолжит выполнение без ожидания SomeMethod, что может привести к неожиданному поведению. Хотя await внутри async void метода корректно дождется завершения асинхронных операций внутри него, вызывающий код не сможет ожидать сам метод.

Использование async Task вместо async void решает проблему ожидания:

public async Task SomeTaskMethod()
{
    await Task.Delay(1000);
    Console.WriteLine("Завершено");
}

public async Task CallMethod()
{
    await SomeTaskMethod();
    Console.WriteLine("Этот код выполнится только после завершения SomeTaskMethod");
}

Теперь CallMethod корректно ждет завершения SomeTaskMethod.

Проблемы с тестированием

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

[Test]
public async Task TestAsyncMethod()
{
    await myService.SomeAsyncMethod(); // Можно ожидать
}

[Test]
public void TestAsyncVoidMethod()
{
    myService.SomeAsyncVoidMethod(); // Невозможно ожидать выполнения
}

Второй тест не будет корректно дожидаться выполнения SomeAsyncVoidMethod.


Использование async void приводит к потере контроля над выполнением задачи, невозможности обработки исключений и проблемам с тестированием. Исключение составляют обработчики событий, где async void неизбежен. Для всех остальных сценариев следует использовать async Task, чтобы обеспечить предсказуемое поведение и возможность управления выполнением задачи.