Наша цель - изучить ответ на вопрос: «что происходит, когда исключения возникают внутри асинхронных операций?»

Немного контекста, прежде чем мы начнем:

Асинхронные операции - это все, что требует времени для завершения (например, чтение из файлов, открытие соединений с БД), но нам не нужно ждать их завершения, чтобы выполнить другой несвязанный код.

Мы рассмотрим TAP (Асинхронный шаблон на основе задач), который в настоящее время является наиболее часто используемым способом обработки асинхронных операций в C #. И, более конкретно, в целях примеров мы рассмотрим асинхронные методы, представленные с помощью ключевых слов async и await, поскольку именно с ними мы сталкиваемся чаще всего (async - await - это просто синтаксический сахар, в котором компилятор C # автоматически создает и возвращает Task , снимая нагрузку с программиста)

Давайте займемся этим !!

Когда в методе async-await создается исключение, возвращенная задача содержит созданное исключение в свойстве Task.Exception. Это AggregateException, и мы можем получить доступ ко всем исключениям, вызвавшим сбой, из его свойства InnerExceptions. В приведенном выше сценарии важно понимать, что если это метод async-await, который вызывает исключение, нам не нужно обрабатывать исключение в вызывающем коде , если мы не ожидаем возвращенной задачи. из метода async-await. Исключение обрабатывается внутри и просто упаковывается в возвращенную задачу (которую мы можем прочитать, чтобы определить причину исключения).

ВЫХОД:

Это отличается от сценария, в котором исключение создается асинхронным методом, который вручную возвращает задачу. В этом случае исключение необходимо обработать с помощью try-catch в вызывающем коде, иначе оно приведет к сбою программы, точно так же, как исключения ведут себя с синхронными методами.

ВЫХОД:

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

Однако есть некоторые предостережения.

Будет разница, если мы сделаем следующее:

- Ждите

OR

- вызвать Wait () / Result

для Задачи, возвращенной в вызывающем коде, если асинхронный метод вызывает исключение. Это поведение одинаково для асинхронного метода async-await и асинхронного метода, который вручную возвращает Task. Что отличает поведение здесь, так это то, выбираем ли мы ожидание или вызов Wait () / Result для Задачи, возвращаемой из асинхронного метода.

  1. Если мы ожидаем возврата Task, то вызывающий код должен обрабатывать первое исключение, содержащееся в AggregateException, а не само AggregateException.

ВЫХОД:

2. И если мы вызываем Wait () / Result для Задачи, возвращенной в вызывающем коде, тогда нам нужно обработать AggregateException. Затем мы можем прочитать свойство InnerExceptions объекта AggregateException и обработать каждое исключение по мере необходимости.

ВЫХОД:

Что происходит, когда возникает исключение в одной или нескольких Задачах, составляющих другую Задачу?

Задача может состоять из одной или нескольких задач (с помощью комбинаторов, таких как Task.WhenAny () или Task.WhenAll ()). В этом случае, если в одной или нескольких Задачах компонента возникает исключение, выполнение всей Задачи не останавливается. Если бы это было так, то некоторые из других задач компонентов (в которых не было исключения) никогда не смогли бы быть выполнены. Вместо этого компилятор C # внутренне обрабатывает эти исключения и упаковывает их в AggregateException. Мы можем получить доступ к отдельным исключениям через свойство InnerExceptions AggregateException.

ВЫХОД:

И последнее, о чем следует помнить, - это то, что когда асинхронный метод генерирует исключение, статус его возвращенной Задачи устанавливается на Сбой.

ВЫХОД: