Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ Программирование на С# _Хотов.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.22 Mб
Скачать
        1. Обработка исключений в async void-методах

В методах, возвращающих void, трудно перехватывать исключения:

static async void SubMethod(int x)

{

await Task.Delay(500);

if (x < 1)

throw new Exception("Число не должно быть меньше 1");

}

static void MainMethod()

{

try

{

SubMethod(0);

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

}

Как правило, подобные методы редко нужны, а большинство из них можно свести к методам, возвращающим объекты Task. Либо следует создавать подобные методы в тех случаях, где есть гарантия, что исключение не возникнет.

Кроме того, если нам нельзя изменить возвращаемый тип с void на Task, например, в асинхронных обработчиках событий, то мы можем вынести весь код в Task-метод:

// асинхронный обработчик события

private async void button1_Click(object sender, EventArgs e)

{

Button1ClickAsync(0);

}

// асинхронный метод с реальной логикой обработки события

public async Task Button1ClickAsync(int num)

{

try

{

await SubMethod(num);

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

// асинхронный метод, где может возникнуть ошибка

async Task SubMethod(int x)

{

await Task.Delay(500);

if (x < 1)

throw new Exception("Число не должно быть меньше 1");

}

        1. Обработка нескольких исключений. WhenAll

Если мы ожидаем выполнения сразу нескольких задач, например, с помощью Task.WhenAll, то мы можем получить сразу несколько исключений одномоментно для каждой выполняемой задачи. В этом случае мы можем получить все исключения из свойства Exception.InnerExceptions:

static async Task DoMultipleAsync()

{

Task t1 = MethodAsync("Первая задача");

Task t2 = MethodAsync("Вторая задача");

Task t3 = MethodAsync("Третья задача");

Task allTasks = Task.WhenAll(t1, t2, t3);

try

{

await allTasks;

}

catch (Exception ex)

{

Console.WriteLine("Исключение: " + ex.Message);

Console.WriteLine("IsFaulted: " + allTasks.IsFaulted);

foreach (var inx in allTasks.Exception.InnerExceptions)

{

Console.WriteLine("Внутренне исключение: " + inx.Message);

}

}

}

Хотя блок catch через переменную Exception ex будет получать одно перехваченное исключение, но с помощью коллекцииException.InnerExceptions мы сможем получить инфрмацию обо всех возникших исключениях.

        1. Await в блоках catch и finally

Начиная с версии C# 6.0 в язык была добавлена возможность вызова асинхронного кода в блоках catch и finally. Так, возьмем предыдущий пример с подсчетом факториала:

static void Main(string[] args)

{

DisplayResultAsync(0).GetAwaiter();

Console.Read();

}

static async Task DisplayResultAsync(int num)

{

Task<int> fact = Factorial(num);

try

{

int result = 1;

if (num < 1)

throw new Exception("Число не должно быть меньше 1");

result= await Task.Run(() =>

{

for (int i = 1; i <= num; i++)

{

result *= i;

}

return result;

});

Console.WriteLine("Факториал числа {0} равен {1}", num, result);

}

catch (Exception ex)

{

await Log(ex);

}

finally

{

await Task.Run(() => Console.WriteLine("await в блоке finally"));

}

}

static async Task Log(Exception ex)

{

await Task.Run(() =>

{

Console.WriteLine(ex);

});

}

Поскольку в метод нахождения факториала передается число меньше 1, то будет выброшено исключение, и сработает блок catch и асинхронный вызов await Log(ex).