Обработчик ошибок си шарп

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

Иногда при выполнении программы возникают ошибки, которые трудно предусмотреть или предвидеть, а иногда и вовсе невозможно. Например, при передачи файла по сети может неожиданно оборваться сетевое подключение. такие ситуации называются исключениями . Язык C# предоставляет разработчикам возможности для обработки таких ситуаций. Для этого в C# предназначена конструкция try. catch. finally .

При использовании блока try. catch..finally вначале выполняются все инструкции в блоке try . Если в этом блоке не возникло исключений, то после его выполнения начинает выполняться блок finally . И затем конструкция try..catch..finally завершает свою работу.

Если же в блоке try вдруг возникает исключение, то обычный порядок выполнения останавливается, и среда CLR начинает искать блок catch , который может обработать данное исключение. Если нужный блок catch найден, то он выполняется, и после его завершения выполняется блок finally.

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

Рассмотрим следующий пример:

int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); Console.WriteLine("Конец программы");

В данном случае происходит деление числа на 0, что приведет к генерации исключения. И при запуске приложения в режиме отладки мы увидим в Visual Studio окошко, которое информирует об исключении:

Исключения в C#

В этом окошке мы видим, что возникло исключение, которое представляет тип System.DivideByZeroException , то есть попытка деления на ноль. С помощью пункта View Details можно посмотреть более детальную информацию об исключении.

И в этом случае единственное, что нам остается, это завершить выполнение программы.

Чтобы избежать подобного аварийного завершения программы, следует использовать для обработки исключений конструкцию try. catch. finally . Так, перепишем пример следующим образом:

try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > catch < Console.WriteLine("Возникло исключение!"); >finally < Console.WriteLine("Блок finally"); >Console.WriteLine("Конец программы");

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

выполнение программы остановится. CLR найдет блок catch и передаст управление этому блоку.

После блока catch будет выполняться блок finally.

Возникло исключение! Блок finally Конец программы

Таким образом, программа по-прежнему не будет выполнять деление на ноль и соответственно не будет выводить результат этого деления, но теперь она не будет аварийно завершаться, а исключение будет обрабатываться в блоке catch.

Следует отметить, что в этой конструкции обязателен блок try . При наличии блока catch мы можем опустить блок finally:

И, наоборот, при наличии блока finally мы можем опустить блок catch и не обрабатывать исключение:

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

Обработка исключений и условные конструкции

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

Square("12"); // Квадрат числа 12: 144 Square("ab"); // !Исключение void Square(string data) < int x = int.Parse(data); Console.WriteLine($"Квадрат числа : "); >

Если пользователь передаст в метод не число, а строку, которая содежит нецифровые символы, то программа выпадет в ошибку. С одной стороны, здесь как раз та ситуация, когда можно применить блок try..catch , чтобы обработать возможную ошибку. Однако гораздо оптимальнее было бы проверить допустимость преобразования:

Square("12"); // Квадрат числа 12: 144 Square("ab"); // Некорректный ввод void Square(string data) < if (int.TryParse(data, out var x)) < Console.WriteLine($"Квадрат числа : "); > else < Console.WriteLine("Некорректный ввод"); >>

Метод int.TryParse() возвращает true , если преобразование можно осуществить, и false — если нельзя. При допустимости преобразования переменная x будет содержать введенное число. Так, не используя try. catch можно обработать возможную исключительную ситуацию.

С точки зрения производительности использование блоков try..catch более накладно, чем применение условных конструкций. Поэтому по возможности вместо try..catch лучше использовать условные конструкции на проверку исключительных ситуаций.

Источник

Обработка исключений (Руководство по программированию на 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 в конце блока.

Несколько блоков 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#.

См. также

Источник

Использование исключений

В C# ошибки в программе в среде выполнения передаются через программу с помощью механизма, который называется исключениями. Исключения вызываются кодом, который встречает ошибку, и перехватываются кодом, который может ее исправить. Исключения могут вызываться средой выполнения .NET или кодом в программе. Вызванное исключение передается вверх по стеку вызовов, пока не будет найден соответствующий оператор catch . Не перехваченные исключения обрабатываются универсальным обработчиком исключений, предоставляемым системой, которая отображает диалоговое окно.

Исключения представляются классами, производными от Exception. Этот класс определяет тип исключения и содержит свойства с подробными сведениями об исключении. При вызове исключения создается экземпляр производного класса, а также могут настраиваться свойства исключения. После этого с помощью ключевого слова throw вызывается объект. Пример:

class CustomException : Exception < public CustomException(string message) < >> private static void TestThrow()

После выдачи исключения среда выполнения проверяет, входит ли текущий оператор в блок try . Если да, она проверяет, может ли какой-либо из блоков catch , связанных с блоком try , перехватить исключение. Блоки Catch обычно задают типы исключений; если тип блока catch совпадает с типом или базовым классом исключения, блок catch может обработать этот метод. Пример:

try < TestThrow(); >catch (CustomException ex)

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

Оператор try может содержать не один блок catch . Выполняется первый оператор catch , который может обработать исключение; все последующие операторы catch игнорируются, даже если они совместимы. Упорядочить блоки catch от наиболее конкретных (или наиболее производных) до наименее конкретных. Пример:

using System; using System.IO; namespace Exceptions < public class CatchOrder < public static void Main() < try < using (var sw = new StreamWriter("./test.txt")) < sw.WriteLine("Hello"); >> // Put the more specific exceptions first. catch (DirectoryNotFoundException ex) < Console.WriteLine(ex); >catch (FileNotFoundException ex) < Console.WriteLine(ex); >// Put the least specific exception last. catch (IOException ex) < Console.WriteLine(ex); >Console.WriteLine("Done"); > > > 

Прежде чем выполнять блок catch , среда выполнения проверяет наличие блоков finally . Блоки Finally позволяют программисту удалить любое неоднозначное состояние, которое может остаться после прерванного блока try , а также освободить любые внешние ресурсы (включая обработчики графики, соединители баз данных или файловые потоки), не дожидаясь, пока сборщик мусора в среде выполнения завершит эти объекты. Пример:

static void TestFinally() < FileStream? file = null; //Change the path to something that works on your machine. FileInfo fileInfo = new System.IO.FileInfo("./file.txt"); try < file = fileInfo.OpenWrite(); file.WriteByte(0xF); >finally < // Closing the file allows you to reopen it immediately - otherwise IOException is thrown. file?.Close(); >try < file = fileInfo.OpenWrite(); Console.WriteLine("OpenWrite() succeeded"); >catch (IOException) < Console.WriteLine("OpenWrite() failed"); >> 

Если WriteByte() вызывает исключение, то код во втором блоке try , который пытается повторно открыть файл, завершится ошибкой, если file.Close() не вызывается, а файл остается заблокированным. Поскольку блоки finally выполняются, даже если выдается исключение, блок finally в предыдущем примере обеспечивает правильное закрытие файла и помогает избежать ошибки.

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

  • Если исключение возникает в методе завершения, он прерывается, и вызывается базовый метод завершения (если есть).
  • Если стек вызовов содержит статический конструктор или инициализатор статического поля, выдается исключение TypeInitializationException, а исходное исключение назначается свойству InnerException нового исключения.
  • Как только достигается начало потока, он прерывается.

Источник

Читайте также:  HTML email
Оцените статью