Полное руководство по языку программирования С# 14 и платформе .NET 10 / Aсинхронное программирование

Возвращение результата из асинхронного метода

Начальный ⏱ 4 мин чтения 👁 2 🕓 обновлено 11.08.2026

В качестве возвращаемого типа в асинхронном методе должны использоваться типы void, Task, Task<T> или ValueTask<T>

void

При использовании ключевого слова void асинхронный метод ничего не возвращает:


PrintAsync("Hello World");
PrintAsync("Hello METANIT.COM");

Console.WriteLine("Main End");
await Task.Delay(3000); // ждем завершения задач

// определение асинхронного метода
async void PrintAsync(string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}	

Однако асинхронных void-методов следует избегать и следует использовать только там, где эти подобные методы представляют единственный возможный способ определения асинхронного метода. Прежде всего, мы не можем применить к подобным методам оператор await. Также потому что исключения в таких методах сложно обрабатывать, так как они не могут быть перехвачены вне метода. Кроме того, подобные void-методы сложно тестировать.

Тем не менее есть ситуации, где без подобных методов не обойтись - например, при обработке событий:


Account account = new Account();
account.Added += PrintAsync;

account.Put(500);

await Task.Delay(2000); // ждем завершения

// определение асинхронного метода
async void PrintAsync(object? obj, string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}

class Account
{
    int sum = 0;
    public event EventHandler<string>? Added;
    public void Put(int sum)
    {
        this.sum += sum;
        Added?.Invoke(this, $"На счет поступило {sum} $");
    }
}

В данном случае событие Added в классе Account представляет делегат EventHandler, который имеет тип void. Соответственно под это событие можно определить только метод-обработчик с типом void.

Task

Возвращение объекта типа Task:


await PrintAsync("Hello Metanit.com");

// определение асинхронного метода
async Task PrintAsync(string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}

Здесь формально метод PrintAsync не использует оператор return для возвращения результата. Однако если в асинхронном методе выполняется в выражении await асинхронная операция, то мы можем возвращать из метода объект Task.

Для ожидания завершения асинхронной задачи можно применить оператор await. Причем его необязательно использовать непосредственно при вызове задачи. Его можно применить лишь там, где нам нужно гарантировано получить результат задачи или удостовериться, что задача завершена.


var task = PrintAsync("Hello Metanit.com"); // задача начинает выполняться
Console.WriteLine("Main Works");

await task; // ожидаем завершения задачи

// определение асинхронного метода
async Task PrintAsync(string message)
{
    await Task.Delay(0);
    Console.WriteLine(message);
}

Task<T>

Метод может возвращать некоторое значение. Тогда возвращаемое значение оборачивается в объект Task, а возвращаемым типом является Task<T>:


int n1 = await SquareAsync(5);
int n2 = await SquareAsync(6);
Console.WriteLine($"n1={n1}  n2={n2}"); // n1=25  n2=36

async Task<int> SquareAsync(int n)
{
    await Task.Delay(0);
    return n * n;
}

В данном случае метод Square возвращает значение типа int - квадрат числа. Поэтому возвращаемым типом в данном случае является типа Task<int>.

Чтобы получить результат асинхронного метода применяем оператор await при вызове SquareAsync:

int n1 = await SquareAsync(5);

Подобным образом можно получать данные других типов:


Person person = await GetPersonAsync("Tom");
Console.WriteLine(person.Name); // Tom
// определение асинхронного метода
async Task<Person> GetPersonAsync(string name)
{
    await Task.Delay(0);
    return new Person(name);
}
record class Person(string Name);

Опять же получение непосредственных результатов асинхронной задачи можно отложить до того момента, когда они непосредственно нужны:


var square5 = SquareAsync(5);
var square6 = SquareAsync(6);

Console.WriteLine("Остальные действия в методе Main");

int n1 = await square5;
int n2 = await square6;
Console.WriteLine($"n1={n1}  n2={n2}"); // n1=25  n2=36

async Task<int> SquareAsync(int n)
{
    await Task.Delay(0);
    var result = n * n;
    Console.WriteLine($"Квадрат числа {n} равен {result}");
    return result;
}

Пример работы программы (ввывод не детерминирован):

Квадрат числа 5 равен 25
Квадрат числа 6 равен 36
Остальные действия в методе Main
n1=25  n2=36

ValueTask<T>

Использование типа ValueTask<T> во многом аналогично применению Task<T> за исключением некоторых различий в работе с памятью, поскольку ValueTask - структура, которая содержит большее количество полей. Поэтому применение ValueTask вместо Task приводит к копированию большего количества данных и соответственно создает некоторые дополнительные издержки.

Преимуществом ValueTask перед Task является то, что данный тип позволяет избежать дополнительных выделений памяти в хипе. Например, иногда требуется синхронно возвратить некоторое значение. Так, возьмем следующий пример:


var result = await AddAsync(4, 5);
Console.WriteLine(result);

Task<int> AddAsync(int a, int b)
{
    return Task.FromResult(a + b);
}

Здесь метод AddAsync синхронно возвращает некоторое значение - в данном случае сумму двух чисел. С помощью статического метода Task.FromResult можно синхронно возвратить некоторое значение. Однако использование типа Task приведет к выделению дополнительной задачи с сопутствующими выделениями памяти в хипе. ValueTask решает эту задачу:


var result = await AddAsync(4, 5);
Console.WriteLine(result);

ValueTask<int> AddAsync(int a, int b)
{
    return new ValueTask<int>(a + b);
}

В данном случае дополнительный объект Task не будет создаваться и соответственно дополнительная память не будет выделяться. Поэтому ValueTask обычно применяется, когда результат асинхронной операции уже имеется.

При необходимости также можно преобразовать ValueTask в объект Task с помощью метода AsTask():


var getMessage = GetMessageAsync();
string message = await getMessage.AsTask();
Console.WriteLine(message); // Hello

async ValueTask<string> GetMessageAsync()
{
    await Task.Delay(0);
    return "Hello";
}

Проверь себя

📋 Тест по теме «Возвращение результата из асинхронного метода» Тест по теме

Практические задания

Лёгкое Ручная проверка Заполните пропуск в коде (1)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

_____("Hello World");
PrintAsync("Hello METANIT.COM");

Console.WriteLine("Main End");
await Task.Delay(3000); // ждем завершения задач

// определение асинхронного метода
async void PrintAsync(string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (2)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

Account _____ = new Account();
account.Added += PrintAsync;

account.Put(500);

await Task.Delay(2000); // ждем завершения

// определение асинхронного метода
async void PrintAsync(object? obj, string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}

class Account
{
    int sum = 0;
    public event EventHandler<string>? Added;
    public void Put(int sum)
    {
        this.sum += sum;
        Added?.Invoke(this, $"На счет поступило {sum} $");
    }
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (3)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

await PrintAsync("_____ Metanit.com");

// определение асинхронного метода
async Task PrintAsync(string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (4)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

var task = PrintAsync("Hello _____.com"); // задача начинает выполняться
Console.WriteLine("Main Works");

await task; // ожидаем завершения задачи

// определение асинхронного метода
async Task PrintAsync(string message)
{
    await Task.Delay(0);
    Console.WriteLine(message);
}
Войдите, чтобы отправить решение
Лёгкое Ручная проверка Заполните пропуск в коде (5)
+10 XP

В приведённом ниже фрагменте кода из этого урока пропущено одно слово. Определите его и впишите в поле ответа (без кавычек и пробелов).

int n1 = await _____(5);
int n2 = await SquareAsync(6);
Console.WriteLine($"n1={n1}  n2={n2}"); // n1=25  n2=36

async Task<int> SquareAsync(int n)
{
    await Task.Delay(0);
    return n * n;
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (1)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

PrintAsync("Hello World");
PrintAsync("Hello METANIT.COM");

Console.WriteLine("Main _____");
await Task.Delay(3000); // ждем завершения задач

// определение асинхронного метода
async void PrintAsync(string _____)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Восстановите код по памяти (2)
+20 XP

В этом фрагменте кода урока пропущены два ключевых элемента. Впишите оба пропущенных значения через запятую в порядке появления (например: x, 5).

Account account = new Account();
account.Added += _____;

account.Put(500);

await Task.Delay(2000); // ждем завершения

// определение асинхронного метода
async void PrintAsync(object? obj, string message)
{
    await Task.Delay(_____);     // имитация продолжительной работы
    Console.WriteLine(message);
}

class Account
{
    int sum = 0;
    public event EventHandler<string>? Added;
    public void Put(int sum)
    {
        this.sum += sum;
        Added?.Invoke(this, $"На счет поступило {sum} $");
    }
}
Войдите, чтобы отправить решение
Среднее Ручная проверка Расставьте строки кода в правильном порядке
+20 XP

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

    await Task.Delay(1000);     // имитация продолжительной работы
}
async Task PrintAsync(string message)
    Console.WriteLine(message);
// определение асинхронного метода
await PrintAsync("Hello Metanit.com");
{
Войдите, чтобы отправить решение
Сложное Ручная проверка Объясните и модифицируйте пример из урока «Возвращение результата из асинхронного метода»
+30 XP

Опишите своими словами, что делает приведённый пример кода из урока «Возвращение результата из асинхронного метода», и предложите одно осмысленное изменение (например, другое входное значение или дополнительное условие). Приведите итоговый код.

PrintAsync("Hello World");
PrintAsync("Hello METANIT.COM");

Console.WriteLine("Main End");
await Task.Delay(3000); // ждем завершения задач

// определение асинхронного метода
async void PrintAsync(string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}
Войдите, чтобы отправить решение
Сложное Ручная проверка Найдите потенциальную проблему в коде урока «Возвращение результата из асинхронного метода»
+30 XP

Изучите приведённый фрагмент кода и опишите, при каких входных данных или условиях он может сработать не так, как ожидается (граничный случай, отсутствие проверки и т.п.). Предложите исправленный вариант.

Account account = new Account();
account.Added += PrintAsync;

account.Put(500);

await Task.Delay(2000); // ждем завершения

// определение асинхронного метода
async void PrintAsync(object? obj, string message)
{
    await Task.Delay(1000);     // имитация продолжительной работы
    Console.WriteLine(message);
}

class Account
{
    int sum = 0;
    public event EventHandler<string>? Added;
    public void Put(int sum)
    {
        this.sum += sum;
        Added?.Invoke(this, $"На счет поступило {sum} $");
    }
}
Войдите, чтобы отправить решение
Мини-проект Ручная проверка Мини-проект по теме «Возвращение результата из асинхронного метода»
+50 XP

Соберите небольшую программу, которая последовательно демонстрирует ключевые идеи урока. Программа должна быть рабочей и содержать минимум два самостоятельно написанных фрагмента, а не просто копию примера из урока.

Войдите, чтобы отправить решение
Домашнее задание Ручная проверка Домашнее задание по теме «Возвращение результата из асинхронного метода»
+25 XP

Напишите собственную небольшую программу, применяющую материал темы «Возвращение результата из асинхронного метода». Используйте не менее одной конструкции, показанной в примерах урока. Прикрепите код решения и краткое описание того, что он делает.

Войдите, чтобы отправить решение

Обсуждение (0)

Войдите, чтобы оставить комментарий.