Операторы обработки исключений — throw
, try-catch
, try-finally
и try-catch-finally
Операторы throw
и try
используются для работы с исключениями. Используйте оператор ,throw
чтобы создать исключение. Используйте инструкцию для перехвата try
и обработки исключений, которые могут возникнуть во время выполнения блока кода.
Инструкция throw
Оператор throw
создает исключение:
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
throw e;
В операторе результат выражения e
должен быть неявно преобразован в System.Exception.
Можно использовать встроенные классы исключений, например или ArgumentOutOfRangeExceptionInvalidOperationException. .NET также предоставляет вспомогательные методы для создания исключений в определенных условиях: ArgumentNullException.ThrowIfNull и ArgumentException.ThrowIfNullOrEmpty. Вы также можете определить собственные классы исключений, производные от System.Exception. Дополнительные сведения см. в разделе Создание и создание исключений.
catch
Внутри блока можно использовать throw;
оператор , чтобы повторно создать исключение, которое обрабатывается блокомcatch
:
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
Примечание
throw;
сохраняет исходную трассировку стека исключения, которая хранится в свойстве Exception.StackTrace . В отличие от этого, throw e;
обновляет StackTrace свойство объекта e
.
При возникновении исключения среда CLR ищет catch
блок , который может обрабатывать это исключение. Если текущий выполняемый catch
метод не содержит такого блока, среда CLR просматривает метод, который вызвал текущий метод, и т. д. в стеке вызовов. Если блок не catch
найден, среда CLR завершает выполнение потока. Дополнительные сведения см. в разделе Как обрабатываются исключенияспецификации языка C#.
Выражение throw
Можно также использовать throw
в качестве выражения. Это может быть удобно в ряде случаев, в том числе:
Условный оператор. В следующем примере выражение используется
throw
для создания , ArgumentException если переданный массивargs
пуст:string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");
Оператор объединения с NULL. В следующем примере выражение используется
throw
для создания , ArgumentNullException если строка, назначаемая свойству, имеет значениеnull
:public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }
Метод или лямбда, воплощающие выражение. В следующем примере используется
throw
выражение для создания , InvalidCastException чтобы указать, что преобразование в DateTime значение не поддерживается:DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
Инструкция try
Оператор можно использовать try
в любой из следующих форм: try-catch
— для обработки исключений, которые могут возникнуть во время выполнения кода внутри try
блока, — для указания кода, try-finally
выполняемого при выходе try
элемента управления из блока, и try-catch-finally
— в виде сочетания двух предыдущих форм.
Инструкция try-catch
Используйте инструкцию для try-catch
обработки исключений, которые могут возникнуть во время выполнения блока кода. Поместите код в том месте, где может возникнуть исключение, try
внутри блока. Используйте предложение catch , чтобы указать базовый тип исключений, которые необходимо обработать в соответствующем catch
блоке:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Можно указать несколько предложений catch:
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
При возникновении исключения предложения catch проверяются в указанном порядке сверху вниз. Максимум для любого созданного исключения выполняется только один catch
блок. Как показано в предыдущем примере, можно опустить объявление переменной исключения и указать только тип исключения в предложении catch. Предложение catch без указанного типа исключения соответствует любому исключению и, если оно имеется, должно быть последним предложением catch.
Если вы хотите повторно создать перехваченное исключение, используйте инструкциюthrow
, как показано в следующем примере:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
Примечание
throw;
сохраняет исходную трассировку стека исключения, которая хранится в свойстве Exception.StackTrace . В отличие от этого, throw e;
обновляет StackTrace свойство объекта e
.
Фильтр исключений when
Наряду с типом исключения можно также указать фильтр исключений, который дополнительно проверяет исключение и решает, обрабатывает ли соответствующий catch
блок это исключение. Фильтр исключений — это логическое выражение, следующее when
за ключевое слово, как показано в следующем примере:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
В предыдущем примере фильтр исключений используется для предоставления одного catch
блока для обработки исключений двух указанных типов.
Можно указать несколько catch
предложений для одного и того же типа исключения, если они различаются фильтрами исключений. Одно из этих предложений может не иметь фильтра исключений. Если такое предложение существует, оно должно быть последним из предложений, указывающих этот тип исключения.
catch
Если предложение содержит фильтр исключений, оно может указать тип исключения, который совпадает с типом исключения предложения, который отображается после него, или меньше производного от catch
него. Например, если присутствует фильтр исключений catch (Exception e)
, предложение не обязательно должно быть последним предложением.
Исключения в асинхронных методах итератора
Если в асинхронной функции возникает исключение, оно распространяется на вызывающий объект функции при ожидании результата функции, как показано в следующем примере:
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
Если в методе итератора возникает исключение, оно распространяется на вызывающий объект только при переходе итератора к следующему элементу.
Инструкция try-finally
try-finally
В инструкции finally
блок выполняется, когда элемент управления покидает try
блок. Элемент управления может покинуть try
блок в результате
- нормальное выполнение,
- выполнение оператора перехода (т. е.
return
,break
,continue
илиgoto
) или - распространение исключения из
try
блока.
В следующем примере блок используется finally
для сброса состояния объекта до того, как элемент управления покинет метод .
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
Вы также можете использовать блок для очистки finally
выделенных ресурсов, используемых в блоке try
.
Примечание
Если тип ресурса реализует IDisposable интерфейс или IAsyncDisposable , рассмотрите инструкциюusing
. Инструкция using
гарантирует, что полученные ресурсы будут удалены, когда элемент управления покидает инструкцию using
. Компилятор преобразует using
оператор в try-finally
оператор .
Почти во всех случаях finally
выполняются блоки. Единственными случаями, когда finally
блоки не выполняются, является немедленное завершение программы. Например, такое завершение может произойти из-за Environment.FailFast вызова или OverflowException исключения или InvalidProgramException . Большинство операционных систем выполняют разумную очистку ресурсов в рамках остановки и выгрузки процесса.
Инструкция try-catch-finally
Оператор используется try-catch-finally
как для обработки исключений, которые могут возникнуть во время выполнения try
блока, так и для указания кода, который должен выполняться при выходе try
из оператора control:
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
Когда исключение обрабатывается блоком catch
, finally
блок выполняется после выполнения этого catch
блока (даже если во время выполнения блока возникает другое catch
исключение). Сведения о catch
блоках и finally
см. в разделах Оператор try-catch
и Оператор try-finally
соответственно.
Спецификация языка C#
Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:
См. также раздел
.NET feedback
The .NET documentation is open source. Provide feedback here.
Обратная связь
Отправить и просмотреть отзыв по