Написание фильтра исключений
Исключение можно обработать посредством перехода на уровень обработчика исключений или путем продолжения выполнения. Вместо использования кода обработчика исключений для обработки исключения и падения можно использовать выражение фильтра для очистки проблемы. Затем, возвращая EXCEPTION_CONTINUE_EXECUTION (-1), вы можете возобновить обычный поток без очистки стека.
После некоторых исключений возобновление невозможно. Если фильтр оценивается как -1 для такого исключения, система вызывает новое исключение. При вызове RaiseException определите, будет ли продолжаться исключение.
Например, следующий код использует вызов функции в выражении фильтра : эта функция обрабатывает проблему, а затем возвращает -1 для возобновления нормального потока управления:
// exceptions_Writing_an_Exception_Filter.cpp #include int main() < int Eval_Exception( int ); __try <>__except ( Eval_Exception( GetExceptionCode( ))) < ; >> void ResetVars( int ) <> int Eval_Exception ( int n_except ) < if ( n_except != STATUS_INTEGER_OVERFLOW && n_except != STATUS_FLOAT_OVERFLOW ) // Pass on most exceptions return EXCEPTION_CONTINUE_SEARCH; // Execute some code to clean up problem ResetVars( 0 ); // initializes data to 0 return EXCEPTION_CONTINUE_EXECUTION; >
Рекомендуется использовать вызов функции в выражении фильтра всякий раз, когда фильтру нужно сделать что-либо сложное. Вычисление выражения приводит к выполнению функции, в данном случае — Eval_Exception .
Обратите внимание на использование GetExceptionCode для определения исключения. Эта функция должна вызываться внутри выражения фильтра инструкции __except . Eval_Exception не может вызываться GetExceptionCode , но он должен иметь код исключения, переданный в него.
Если исключение не вызвано переполнением при операции с целыми числами или числами с плавающей запятой, этот обработчик передает управление другому обработчику. В этом случае обработчик вызывает функцию ( ResetVars — это только пример, а не функция API), чтобы сбросить некоторые глобальные переменные. Блок инструкций __except , который в этом примере пуст, никогда не может выполняться, так как Eval_Exception никогда не возвращает EXCEPTION_EXECUTE_HANDLER (1).
Вызов функции — хороший способ работы со сложными выражениями фильтров. Удобны также две другие возможности языка C:
- условный оператор;
- оператор «запятая».
Условный оператор часто используется здесь. Его можно использовать для проверка для определенного кода возврата, а затем возвращать одно из двух разных значений. Например, фильтр в следующем коде распознает исключение только в том случае, если исключение: STATUS_INTEGER_OVERFLOW
__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 )
Цель условного оператора в этом случае — в основном, обеспечить ясность, так как следующий код дает такие же результаты.
__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW )
Условный оператор более полезен в ситуациях, когда фильтр может иметь значение -1. EXCEPTION_CONTINUE_EXECUTION
Оператор запятых позволяет выполнять несколько выражений в последовательности. Затем он возвращает значение последнего выражения. Например, в следующем коде код исключения сохраняется в переменной и затем проверяется.
__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )
С чего начинается фильтр исключений в конструкции
За обработку исключения отвечает блок catch , который может иметь следующие формы:
catch < // выполняемые инструкции >
catch (тип_исключения) < // выполняемые инструкции >
Обрабатывает только те исключения, которые соответствуют типу, указаному в скобках после оператора catch. Например, обработаем только исключения типа DivideByZeroException:
try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > catch(DivideByZeroException)
catch (тип_исключения имя_переменной) < // выполняемые инструкции >
Обрабатывает только те исключения, которые соответствуют типу, указаному в скобках после оператора catch. А вся информация об исключении помещается в переменную данного типа. Например:
try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > catch(DivideByZeroException ex) < Console.WriteLine($"Возникло исключение "); >
Фильтры исключений
Фильтры исключений позволяют обрабатывать исключения в зависимости от определенных условий. Для их применения после выражения catch идет выражение when , после которого в скобках указывается условие:
catch when(условие)
В этом случае обработка исключения в блоке catch производится только в том случае, если условие в выражении when истинно. Например:
int x = 1; int y = 0; try < int result1 = x / y; int result2 = y / x; >catch (DivideByZeroException) when (y == 0) < Console.WriteLine("y не должен быть равен 0"); >catch(DivideByZeroException ex)
В данном случае будет выброшено исключение, так как y=0. Здесь два блока catch, и оба они обрабатывают исключения типа DivideByZeroException, то есть по сути все исключения, генерируемые при делении на ноль. Но поскольку для первого блока указано условие y == 0 , то именно этот блок будет обрабатывать данное исключение - условие, указанное после оператора when возвращает true.
int x = 0; int y = 1; try < int result1 = x / y; int result2 = y / x; >catch (DivideByZeroException) when (y == 0) < Console.WriteLine("y не должен быть равен 0"); >catch(DivideByZeroException ex)
В данном случае будет выброшено исключение, так как x=0. Условие первого блока catch - y == 0 теперь возвращает false. Поэтому CLR будет дальше искать соответствующие блоки catch далее и для обработки исключения выберет второй блок catch. В итоге если мы уберем второй блок catch, то исключение вообще не будет обрабатываться.
С чего начинается фильтр исключений в конструкции
Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Последнее обновление: 31.10.2015
Фильтры исключений срабатывают, если при выполнении метода действия будет выброшено необработанное исключение.
С одной стороны, мы могли поместить всю логику выполнения метода в блок try. catch и отследить исключение. Однако область работы фильтров исключения несколько шире. Они позволяют отследить не только исключения, возникающие в самом методе, но исключения, генерируемые результатами действий, а также другими применяемыми к данному действию фильтрами. В этом и состоит мощь данного типа фильтров.
Все фильтры исключений должны применять интерфейс IExceptionFilter :
public interface IExceptionFilter
И если вдруг приложение выбрасывает необрабатываемое исключение, то фильтр вызывает метод OnException .
Передаваемый в этот метод параметр - ExceptionContext является объектом, производным от ControllerContext . Поэтому из него можно извлечь как специфичную для фильтра информацию, так и общую информацию о запросе.
В частности класс ExceptionContext обладает следующими свойствами, которые позволяют получить информацию об исключении:
Содержит информацию о методе действия, на котором было выброшено исключение
Представляет само необработанное исключение
Значение, показывающее, считается ли исключение обработанным. Если мы на фильтре помечаем его значение в true, то исключение считается обработанным
Результат метода действия, к которому применяется фильтр исключения
С помощью свойства Exception мы можем получить доступ к выбрасываемому исключению.
Установив свойство ExceptionHandled в true, фильтр тем самым помечает исключение как обработанное.
С помощью свойства Result фильтр управляет результатом действий. Общераспространенной практикой в данном случае является перенаправление пользователя на страницу ошибки или отображение ошибки на экране.
Теперь создадим простенький фильтр, который будет обрабатывать исключение IndexOutOfRangeException :
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters.Filters < public class IndexException : FilterAttribute, IExceptionFilter < public void OnException(ExceptionContext exceptionContext) < if (!exceptionContext.ExceptionHandled && exceptionContext.Exception is IndexOutOfRangeException) < exceptionContext.Result = new RedirectResult("/Content/ExceptionFound.html"); exceptionContext.ExceptionHandled = true; >> > >
Здесь в методе OnException первым делом мы проверяем, не установлено ли значение свойства ExceptionHandled . Если оно установлено в true, следовательно, какой-то другой фильтр исключений уже обработал данное исключение. Также проверяется тип исключения. Поскольку мы ловим в данном случае только исключения типа IndexOutOfRangeException , следовательно, нас только они интересуют.
Далее мы устанавливаем результат метода, к которому применен фильтр. Предполагается, что в проекте в каталоге Content у нас находится некоторая страница ExceptionFound.html, которая отображает пользователю сообщение об ошибке.
В данном случае важно пометить исключение как обработанное: exceptionContext.ExceptionHandled = true . Иначе, если мы этого не сделаем, то мы можем увидеть в браузере все диагностическое сообщение об ошибке, которое обычно посылает фреймворк в ответ клиенту.
[IndexException] public ActionResult Index()
В данном случае метод Index выбросит необработанное исключение, и оно будет объектом типа IndexOutOfRangeException , а пользователь будет перенаправлен на страницу ExceptionFound.html .
Подобным образом мы можем обработать и другие типы исключений.
HandleErrorAttribute. Встроенная обработка исключений.
Создавать свои фильтры исключений необязательно, так как во фреймворке имеется встроенная реализация интерфейса IExceptionFilter - атрибут HandleErrorAttribute. Он имеет ряд свойств, с помощью которых мы можем произвести гибкую настройку фильтра:
Представляет тип обрабатываемого исключения. По умолчанию используется System.Exception
Имя представления, которое рендерится данным фильтром. Если значение не задано, то по умолчанию используются следующие пути: /Views/Имя_контроллера/Error.cshtml или /Views/Shared/Error.cshtml
Имя используемой мастер-страницы
При обработке исключения фильтр исключений посылает статусный код HTTP 500 и генерирует указанное в свойстве View представление. Например, используем предыдущий пример с фильтром исключений, применив встроенную реализацию:
[HandleError(ExceptionType = typeof(System.IndexOutOfRangeException), View = "ExceptionFound")] public ActionResult About()
В данном случае очевидно, что на строке mas[6] = 4; будет выброшено исключение. В режиме отладки у вас приостановится выполнение программы, тогда вы можете нажать на кнопку Continue на панели инструментов. Здесь опять мы обрабатываем исключение типа IndexOutOfRangeException, и при возникновении такового генерируем в ответ представление ExceptionFound.cshtml . Данное представление должно находиться в проекте в каталоге Views/Имя_контроллера/ .
Сразу надо сказать, что если вы хотите при разработке видеть обрабатываемые фильтром HandleErrorAttribute, то надо включить данную функциональность в файле конфигурации web.config с помощью тега :
Try. Catch. Finally Оператор (Visual Basic)
Предоставляет способ обработки некоторых или всех возможных ошибок, которые могут возникнуть в заданном блоке кода, при этом все еще выполняется код.
Синтаксис
Try [ tryStatements ] [ Exit Try ] [ Catch [ exception [ As type ] ] [ When expression ] [ catchStatements ] [ Exit Try ] ] [ Catch . ] [ Finally [ finallyStatements ] ] End Try
Детали
| Термин | Определение |
|---|---|
| tryStatements | Необязательно. Операторы, в которых может возникнуть ошибка. Может быть составным оператором. |
| Catch | Необязательно. Разрешено несколько Catch блоков. Если при обработке Try блока возникает исключение, каждая Catch инструкция проверяется в текстовом порядке, чтобы определить, обрабатывает ли оно исключение, представляющее exception исключение, которое было создано. |
| exception | Необязательно. Любое имя переменной. Начальное значение exception — это значение возникшей ошибки. Используется для Catch указания ошибки, поймаемой. Если опущено, Catch инструкция перехватывает любое исключение. |
| type | Необязательно. Задает тип фильтра классов. Если значение exception имеет тип, указанный type или производным типом, идентификатор становится привязанным к объекту исключения. |
| When | Необязательно. Оператор Catch с предложением When перехватывает исключения только при expression вычислении True . Предложение When применяется только после проверка типа исключения и expression может ссылаться на идентификатор, представляющий исключение. |
| expression | Необязательно. Должен быть неявно преобразован в Boolean . Любое выражение, описывающее универсальный фильтр. Обычно используется для фильтрации по номеру ошибки. Используется с When ключевое слово для указания обстоятельств, при которых обнаружена ошибка. |
| catchStatements | Необязательно. Операторы для обработки ошибок, возникающих в связанном Try блоке. Может быть составным оператором. |
| Exit Try | Необязательно. Ключевое Try. Catch. Finally слово, которое прерывается из структуры. Выполнение возобновляется с помощью кода сразу после инструкции End Try . Инструкция Finally по-прежнему будет выполнена. Запрещено в Finally блоках. |
| Finally | Необязательно. Finally Блок всегда выполняется, когда выполнение покидает любую часть инструкции Try. Catch . |
| finallyStatements | Необязательно. Операторы, которые выполняются после выполнения всей другой обработки ошибок. |
| End Try | Завершает структуру Try. Catch. Finally . |
Замечания
Если вы ожидаете, что определенное исключение может возникать во время определенного раздела кода, поместите код в Try блок и используйте Catch блок для сохранения элемента управления и обработки исключения, если это происходит.
Оператор Try…Catch состоит из Try блока, за которым следует одно или несколько Catch предложений, которые указывают обработчики для различных исключений. При возникновении исключения в Try блоке Visual Basic ищет Catch инструкцию, обрабатывающую исключение. Если оператор сопоставления Catch не найден, Visual Basic проверяет метод, вызывающий текущий метод, и т. д. Если блок не Catch найден, Visual Basic отображает необработанное сообщение об исключении для пользователя и останавливает выполнение программы.
В инструкции можно использовать несколько Catch инструкций Try…Catch . Если это сделать, порядок Catch предложений является значительным, так как они проверяются в порядке. Catch более конкретные исключения перед менее конкретными.
Catch Следующие условия инструкции являются наименее конкретными и будут перехватывать все исключения, производные от Exception класса. Обычно следует использовать один из этих вариантов в качестве последнего Catch блока в Try. Catch. Finally структуре после перехвата всех ожидаемых исключений. Поток управления никогда не может достичь Catch блока, следующего за любой из этих вариантов.
- Например, это type : Exception Catch ex As Exception
- Оператор не exception имеет переменной, например: Catch
Try…Catch…Finally Когда инструкция вложена в другой Try блок, Visual Basic сначала проверяет каждую Catch инструкцию в самом Try внутреннем блоке. Если оператор сопоставления Catch не найден, поиск переходит к Catch операторам внешнего Try…Catch…Finally блока.
Локальные переменные из Try блока недоступны в блоке Catch , так как они являются отдельными блоками. Если вы хотите использовать переменную в нескольких блоках, объявите переменную за пределами Try. Catch. Finally структуры.
Инструкция Try…Catch…Finally доступна в виде фрагмента кода IntelliSense. В диспетчере фрагментов кода разверните шаблоны кода : If, For Each, TryCatchProperty и т. д., а затем Обработка ошибок (исключения). Для получения дополнительной информации см. Code Snippets.
Блок Finally
Если у вас есть одна или несколько инструкций, которые должны выполняться перед выходом Try Finally из структуры, используйте блок. Элемент управления передается Finally блоку непосредственно перед тем, как он выходит из Try…Catch структуры. Это верно, даже если исключение происходит в любой точке Try структуры.
Блок Finally полезен для выполнения любого кода, который должен выполняться, даже если существует исключение. Элемент управления передается блоку Finally независимо от Try. Catch способа выхода блока.
Код в блоке Finally выполняется, даже если код встречает Return инструкцию в блоке Try или Catch блоке. Элемент управления не передается из Try блока или Catch блока в соответствующий Finally блок в следующих случаях:
- Оператор End обнаруживается в блоке или Catch блоке Try .
- Вызывается StackOverflowException в блоке Try или Catch блоке.
Недопустимо явно передавать выполнение в Finally блок. Передача выполнения из Finally блока недопустима, за исключением исключения.
Try Если оператор не содержит хотя бы один Catch блок, он должен содержать Finally блок.
Если вам не нужно перехватывать определенные исключения, Using инструкция ведет себя как Try…Finally блок и гарантирует удаление ресурсов независимо от способа выхода из блока. Это верно даже с необработанным исключением. Дополнительные сведения см. в разделе Оператор using.
Аргумент исключения
Аргумент Catch блока exception — это экземпляр класса или класса, производный Exception от Exception класса. Экземпляр Exception класса соответствует ошибке, которая произошла в блоке Try .
Свойства Exception объекта помогают определить причину и расположение исключения. Например, StackTrace свойство перечисляет вызываемые методы, которые привели к исключению, помогая определить, где произошла ошибка в коде. Message возвращает сообщение, описывающее исключение. HelpLink возвращает ссылку на связанный файл справки. InnerException Exception возвращает объект, вызвавшее текущее исключение, или возвращается Nothing , если исходный Exception объект отсутствует.
Рекомендации при использовании инструкции Try…Catch
Используйте инструкцию Try…Catch только для сигнала о возникновении необычных или непреднамеренных событий программы. Ниже приведены причины для этого:
- CatchИсключения при выполнении создают дополнительные издержки и, скорее всего, будут медленнее, чем предварительно проверка, чтобы избежать исключений.
- Catch Если блок не обрабатывается правильно, это исключение может быть неправильно сообщено пользователям.
- Обработка исключений делает программу более сложной.
Оператору не всегда требуется Try…Catch проверка для условия, которое, скорее всего, произойдет. В следующем примере проверка, существует ли файл перед попыткой открыть его. Это снижает потребность в перехвате исключения, вызываемого методом OpenText .
Private Sub TextFileExample(ByVal filePath As String) ' Verify that the file exists. If System.IO.File.Exists(filePath) = False Then Console.Write("File Not Found: " & filePath) Else ' Open the text file and display its contents. Dim sr As System.IO.StreamReader = System.IO.File.OpenText(filePath) Console.Write(sr.ReadToEnd) sr.Close() End If End Sub
Убедитесь, что код в Catch блоках может правильно сообщать об исключениях пользователям, будь то через потокобезопасный журнал или соответствующие сообщения. В противном случае исключения могут оставаться неизвестными.
Асинхронные методы
Если пометить метод модификатором Async , можно использовать оператор Await в методе. Оператор с оператором Await приостанавливает выполнение метода до завершения ожидаемой задачи. Задача представляет выполняющуюся работу. Когда задача, связанная с оператором Await , завершается, выполнение возобновляется в том же методе. Дополнительные сведения см. в разделе "Поток управления" в асинхронных программах.
Задача, возвращаемая методом Async, может завершиться сбоем, указывая на то, что она завершена из-за необработанного исключения. Задача также может завершиться в отмененном состоянии, что приводит к OperationCanceledException возникновению исключения из выражения await. Чтобы поймать любое исключение, поместите Await выражение, связанное с задачей в Try блоке, и перехватите исключение в блоке Catch . Пример представлен далее в этом разделе.
Задача может находиться в состоянии сбоя, так как несколько исключений отвечают за его сбой. Например, задача может быть результатом вызова метода Task.WhenAll. Когда вы ожидаете такую задачу, выловленное исключение является только одним из исключений, и вы не можете предсказать, какое исключение будет поймано. Пример представлен далее в этом разделе.
Выражение Await не может находиться внутри Catch блока или Finally блока.
Итераторы
Функция итератора или Get метод доступа выполняет настраиваемую итерацию по коллекции. Итератор использует инструкцию Yield для возврата каждого элемента коллекции по одному за раз. Вы вызываете функцию итератора с помощью элемента For Each. Следующая инструкция.
Оператор Yield может находиться внутри Try блока. Блок Try , содержащий инструкцию Yield , может иметь Catch блоки и может иметь Finally блок. Пример см. в разделе Try "Блоки".
Оператор Yield не может находиться внутри Catch блока или Finally блока.
For Each Если тело (вне функции итератора) создает исключение, Catch блок в функции итератора не выполняется, но Finally выполняется блок в функции итератора. Блок Catch внутри функции итератора перехватывает только исключения, происходящие внутри функции итератора.
Ситуации с частичным доверием
В ситуациях с частичным доверием, таких как приложение, размещенное в общей сетевой папке, не перехватывает исключения безопасности, Try. Catch. Finally возникающие перед вызовом метода, содержащего вызов. В следующем примере, когда вы помещаете его в общую папку сервера и запускаете его оттуда, возникает ошибка System.Security.SecurityException: Request Failed. Дополнительные сведения об исключениях безопасности см. в SecurityException классе.
Try Process.Start("http://www.microsoft.com") Catch ex As Exception Console.WriteLine("Can't load Web page" & vbCrLf & ex.Message) End Try
В такой ситуации с частичным доверием необходимо поместить инструкцию Process.Start в отдельный Sub . Первоначальный вызов Sub сбоя. Это позволяет Try. Catch перехватывать его до Sub Process.Start запуска содержащегося и создаваемого исключения безопасности.
Примеры
Структура Try. Catch. Finally
В следующем примере показана структура инструкции Try. Catch. Finally .
Public Sub TryExample() ' Declare variables. Dim x As Integer = 5 Dim y As Integer = 0 ' Set up structured error handling. Try ' Cause a "Divide by Zero" exception. x = x \ y ' This statement does not execute because program ' control passes to the Catch block when the ' exception occurs. Console.WriteLine("end of Try block") Catch ex As Exception ' Show the exception's message. Console.WriteLine(ex.Message) ' Show the stack trace, which is a list of methods ' that are currently executing. Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace) Finally ' This line executes whether or not the exception occurs. Console.WriteLine("in Finally block") End Try End Sub
Исключение в методе, вызываемом Try из блока
В следующем примере CreateException метод создает исключение NullReferenceException . Код, создающий исключение, не находится в блоке Try . CreateException Поэтому метод не обрабатывает исключение. Метод RunSample обрабатывает исключение, так как вызов CreateException метода находится в блоке Try .
В примере содержатся Catch инструкции для нескольких типов исключений, упорядоченные из наиболее конкретных наиболее общих.
Public Sub RunSample() Try CreateException() Catch ex As System.IO.IOException ' Code that reacts to IOException. Catch ex As NullReferenceException Console.WriteLine("NullReferenceException: " & ex.Message) Console.WriteLine("Stack Trace: " & vbCrLf & ex.StackTrace) Catch ex As Exception ' Code that reacts to any other exception. End Try End Sub Private Sub CreateException() ' This code throws a NullReferenceException. Dim obj = Nothing Dim prop = obj.Name ' This code also throws a NullReferenceException. 'Throw New NullReferenceException("Something happened.") End Sub
Оператор When Catch
В следующем примере показано, как использовать Catch When инструкцию для фильтрации по условному выражению. Если условное выражение оценивается True , код в блоке Catch выполняется.
Private Sub WhenExample() Dim i As Integer = 5 Try Throw New ArgumentException() Catch e As OverflowException When i = 5 Console.WriteLine("First handler") Catch e As ArgumentException When i = 4 Console.WriteLine("Second handler") Catch When i = 5 Console.WriteLine("Third handler") End Try End Sub ' Output: Third handler
Вложенные Try операторы
В следующем примере есть Try…Catch инструкция, содержащаяся в блоке Try . Внутренний Catch блок создает исключение, которое имеет свойство InnerException , заданное для исходного исключения. Внешний Catch блок сообщает о своем собственном исключении и внутреннем исключении.
Private Sub InnerExceptionExample() Try Try ' Set a reference to a StringBuilder. ' The exception below does not occur if the commented ' out statement is used instead. Dim sb As System.Text.StringBuilder 'Dim sb As New System.Text.StringBuilder ' Cause a NullReferenceException. sb.Append("text") Catch ex As Exception ' Throw a new exception that has the inner exception ' set to the original exception. Throw New ApplicationException("Something happened :(", ex) End Try Catch ex2 As Exception ' Show the exception. Console.WriteLine("Exception: " & ex2.Message) Console.WriteLine(ex2.StackTrace) ' Show the inner exception, if one is present. If ex2.InnerException IsNot Nothing Then Console.WriteLine("Inner Exception: " & ex2.InnerException.Message) Console.WriteLine(ex2.StackTrace) End If End Try End Sub
Обработка исключений для асинхронных методов
В следующем примере демонстрируется обработка исключений для асинхронных методов. Чтобы поймать исключение, которое применяется к асинхронной задаче, Await выражение находится в Try блоке вызывающего объекта, и исключение перехватывается в блоке Catch .
Раскомментируйте строку Throw New Exception в этом примере для демонстрации обработки исключений. Исключение поймано в блоке Catch , свойство задачи имеет True значение , а свойство задачи IsFaulted Exception.InnerException — исключение.
Раскомментируйте строку Throw New OperationCancelledException , чтобы показать, что происходит при отмене асинхронного процесса. Исключение поймано в блоке Catch , а свойство задачи IsCanceled имеет значение True . Однако в некоторых условиях, которые не применяются к этому примеру, IsFaulted задано True значение и IsCanceled имеет значение False .
Public Async Function DoSomethingAsync() As Task Dim theTask As Task(Of String) = DelayAsync() Try Dim result As String = Await theTask Debug.WriteLine("Result: " & result) Catch ex As Exception Debug.WriteLine("Exception Message: " & ex.Message) End Try Debug.WriteLine("Task IsCanceled: " & theTask.IsCanceled) Debug.WriteLine("Task IsFaulted: " & theTask.IsFaulted) If theTask.Exception IsNot Nothing Then Debug.WriteLine("Task Exception Message: " & theTask.Exception.Message) Debug.WriteLine("Task Inner Exception Message: " & theTask.Exception.InnerException.Message) End If End Function Private Async Function DelayAsync() As Task(Of String) Await Task.Delay(100) ' Uncomment each of the following lines to ' demonstrate exception handling. 'Throw New OperationCanceledException("canceled") 'Throw New Exception("Something happened.") Return "Done" End Function ' Output when no exception is thrown in the awaited method: ' Result: Done ' Task IsCanceled: False ' Task IsFaulted: False ' Output when an Exception is thrown in the awaited method: ' Exception Message: Something happened. ' Task IsCanceled: False ' Task IsFaulted: True ' Task Exception Message: One or more errors occurred. ' Task Inner Exception Message: Something happened. ' Output when an OperationCanceledException or TaskCanceledException ' is thrown in the awaited method: ' Exception Message: canceled ' Task IsCanceled: True ' Task IsFaulted: False
Обработка нескольких исключений в асинхронных методах
В следующем примере демонстрируется обработка исключений, когда несколько задач могут привести к нескольким исключениям. Блок Try содержит Await выражение для возвращаемой задачи Task.WhenAll . Задача завершается, когда выполняются три задачи, к которым Task.WhenAll применяются.
Каждая из трех задач вызывает исключение. Блок Catch выполняет итерацию по исключениям, которые находятся в Exception.InnerExceptions свойстве возвращаемой задачи Task.WhenAll .
Public Async Function DoMultipleAsync() As Task Dim theTask1 As Task = ExcAsync(info:="First Task") Dim theTask2 As Task = ExcAsync(info:="Second Task") Dim theTask3 As Task = ExcAsync(info:="Third Task") Dim allTasks As Task = Task.WhenAll(theTask1, theTask2, theTask3) Try Await allTasks Catch ex As Exception Debug.WriteLine("Exception: " & ex.Message) Debug.WriteLine("Task IsFaulted: " & allTasks.IsFaulted) For Each inEx In allTasks.Exception.InnerExceptions Debug.WriteLine("Task Inner Exception: " + inEx.Message) Next End Try End Function Private Async Function ExcAsync(info As String) As Task Await Task.Delay(100) Throw New Exception("Error-" & info) End Function ' Output: ' Exception: Error-First Task ' Task IsFaulted: True ' Task Inner Exception: Error-First Task ' Task Inner Exception: Error-Second Task ' Task Inner Exception: Error-Third Task
См. также
- Err
- Exception
- Оператор Exit
- Оператор On Error
- Рекомендации по использованию фрагментов кода
- Обработка исключений
- Оператор Throw