Обработка исключений си шарп

Обработка исключений (Руководство по программированию на C#)

Блок try используется программистами C# для разбиения на разделы кода, который может затрагиваться исключением. Связанные с ним блоки catch используются для обработки возможных исключений. Блок finally содержит код, выполняемый вне зависимости от того, вызывается ли исключение в блоке try , например для освобождения ресурсов, выделенных в блоке try . Блоку try требуется один или несколько связанных блоков catch или блок finally (либо и то, и другое).

В приведенных ниже примерах показаны операторы try-catch , try-finally и try-catch-finally .

try < // Code to try goes here. >catch (SomeSpecificException ex) < // Code to handle the exception goes here. // Only catch exceptions that you know how to handle. // Never catch base class System.Exception without // rethrowing it at the end of the catch block. >
try < // Code to try goes here. >catch (SomeSpecificException ex) < // Code to handle the exception goes here. >finally < // Code to execute after the try (and possibly catch) blocks // goes here. >

Блок try без блока catch или блока finally вызовет ошибку компилятора.

Блоки catch

Блок catch может определять тип перехватываемого исключения. Спецификация типа называется фильтром исключений. Тип исключения должен быть производным от Exception. Как правило, не указывайте Exception в качестве фильтра исключений, если вы не знаете, как обрабатывать все исключения, которые могут возникнуть в try блоке, или вы не включили catch инструкцию throw в конце блока.

Читайте также:  React typescript keyboard event

Несколько блоков catch с различными классами исключений могут быть соединены в цепочку. Блоки catch проверяются сверху вниз в коде, однако для каждого вызванного исключения выполняется только один блок catch . Выполняется первый блок catch , в котором указан точный тип или базовый класс вызванного исключения. Если нет блока catch , в котором определен соответствующий класс исключений, выбирается блок catch , в котором нет выбранного типа, если таковой имеется в операторе. Важно, чтобы первыми были размещены блоки catch с самыми конкретными (т. е. самыми производными) типами исключений.

Исключения следует перехватывать при выполнении указанных ниже условий.

  • Вы ясно понимаете возможные причины вызова исключения и можете выполнить восстановление, например, предложив пользователю ввести новое имя файла при перехвате объекта FileNotFoundException.
  • Вы можете создать и вызвать новое, более конкретное исключение.
int GetInt(int[] array, int index) < try < return array[index]; >catch (IndexOutOfRangeException e) < throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); >> 
try < // Try to access a resource. >catch (UnauthorizedAccessException e) < // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; >

Вы также можете указывать фильтры исключений, чтобы добавить логическое выражение в предложение catch. Фильтры исключений указывают, что определенное предложение catch соответствует только в том случае, если условие имеет значение true. В следующем примере оба предложения catch используют один и тот же класс исключения, но проверяется дополнительное условие, чтобы создать другое сообщение об ошибке:

int GetInt(int[] array, int index) < try < return array[index]; >catch (IndexOutOfRangeException e) when (index < 0) < throw new ArgumentOutOfRangeException( "Parameter index cannot be negative.", e); >catch (IndexOutOfRangeException e) < throw new ArgumentOutOfRangeException( "Parameter index cannot be greater than the array size.", e); >> 

Фильтр исключений, который всегда возвращает false , можно использовать для проверки всех исключений, но не для их обработки. Обычно он используется для регистрации исключений:

public static void Main() < try < string? s = null; Console.WriteLine(s.Length); >catch (Exception e) when (LogException(e)) < >Console.WriteLine("Exception must have been handled"); > private static bool LogException(Exception e) < Console.WriteLine($"\tIn the log routine. Caught "); Console.WriteLine($"\tMessage: "); return false; > 

Метод LogException всегда возвращает false , и ни одно предложение catch , использующее этот фильтр, не является соответствующим. Предложение catch может быть общим с использованием System.Exception, а последующие предложения могут обрабатывать более конкретные классы исключений.

Блоки «Finally»

Блок finally позволяет удалить действия, выполненные в блоке try . При наличии блока finally он выполняется последним, после блока try и всех выполняемых блоков catch . Блок finally выполняется всегда, независимо от того, возникло ли исключение, или найден ли блок catch , соответствующий типу исключения.

Блок finally можно использовать для высвобождения ресурсов, например потоков данных, подключений к базам данных, графических дескрипторов, не ожидая финализации объектов сборщиком мусора во время выполнения.

В приведенном ниже примере с помощью блока finally закрывается файл, открытый в блоке try . Обратите внимание, что состояние дескриптора файла проверяется до закрытия файла. Если блок try не может открыть этот файл, то дескриптор файла сохраняет значение null , и блок finally не пытается закрыть его. И наоборот, если файл успешно открыт в блоке try , блок finally закрывает открытый файл.

FileStream? file = null; FileInfo fileinfo = new System.IO.FileInfo("./file.txt"); try < file = fileinfo.OpenWrite(); file.WriteByte(0xF); >finally < // Check for null because OpenWrite might have failed. file?.Close(); >

Спецификация языка C#

Дополнительные сведения см. в разделах Исключения и Оператор try в Спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.

См. также

Источник

Операторы обработки исключений — throw , try-catch , try-finally и try-catch-finally

Операторы throw и try используются для работы с исключениями. Используйте оператор , throw чтобы создать исключение. Используйте инструкцию для перехвата try и обработки исключений, которые могут возникнуть во время выполнения блока кода.

Инструкция throw

Оператор throw создает исключение:

throw e; В операторе результат выражения e должен быть неявно преобразован в System.Exception.

Можно использовать встроенные классы исключений, например или ArgumentOutOfRangeExceptionInvalidOperationException. .NET также предоставляет вспомогательные методы для создания исключений в определенных условиях: ArgumentNullException.ThrowIfNull и ArgumentException.ThrowIfNullOrEmpty. Вы также можете определить собственные классы исключений, производные от System.Exception. Дополнительные сведения см. в разделе Создание и создание исключений.

catch Внутри блока можно использовать throw; оператор , чтобы повторно создать исключение, которое обрабатывается блоком catch :

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."); 
public string Name < get =>name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); > 
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: "); > catch (ArgumentException e) < Console.WriteLine($"Processing failed: "); > 

Можно указать несколько предложений catch:

try < var result = await ProcessAsync(-3, 4, cancellationToken); Console.WriteLine($"Processing succeeded: "); > catch (ArgumentException e) < Console.WriteLine($"Processing failed: "); > catch (OperationCanceledException)

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

Если вы хотите повторно создать перехваченное исключение, используйте инструкцию throw , как показано в следующем примере:

throw; сохраняет исходную трассировку стека исключения, которая хранится в свойстве Exception.StackTrace . В отличие от этого, throw e; обновляет StackTrace свойство объекта e .

Фильтр исключений when

Наряду с типом исключения можно также указать фильтр исключений, который дополнительно проверяет исключение и решает, обрабатывает ли соответствующий catch блок это исключение. Фильтр исключений — это логическое выражение, следующее when за ключевое слово, как показано в следующем примере:

try < var result = Process(-3, 4); Console.WriteLine($"Processing succeeded: "); > catch (Exception e) when (e is ArgumentException || e is DivideByZeroException) < Console.WriteLine($"Processing failed: "); > 

В предыдущем примере фильтр исключений используется для предоставления одного catch блока для обработки исключений двух указанных типов.

Можно указать несколько catch предложений для одного и того же типа исключения, если они различаются фильтрами исключений. Одно из этих предложений может не иметь фильтра исключений. Если такое предложение существует, оно должно быть последним из предложений, указывающих этот тип исключения.

catch Если предложение содержит фильтр исключений, оно может указать тип исключения, который совпадает с типом исключения предложения, который отображается после него, или меньше производного от catch него. Например, если присутствует фильтр исключений catch (Exception e) , предложение не обязательно должно быть последним предложением.

Исключения в асинхронных методах итератора

Если в асинхронной функции возникает исключение, оно распространяется на вызывающий объект функции при ожидании результата функции, как показано в следующем примере:

public static async Task Run() < try < Taskprocessing = ProcessAsync(-1); Console.WriteLine("Launched processing."); int result = await processing; Console.WriteLine($"Result: ."); > catch (ArgumentException e) < Console.WriteLine($"Processing failed: "); > // Output: // Launched processing. // Processing failed: Input must be non-negative. (Parameter 'input') > private static async Task 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 ."); throw; > finally < Busy = false; >> 

Когда исключение обрабатывается блоком catch , finally блок выполняется после выполнения этого catch блока (даже если во время выполнения блока возникает другое catch исключение). Сведения о catch блоках и finally см. в разделах Оператор try-catch и Оператор try-finally соответственно.

Спецификация языка C#

Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#:

См. также раздел

Источник

Оцените статью