Перехват исключений в Visual C++
В этой статье описывается try-catch-finally использование блока для перехвата исключения.
Исходная версия продукта: Visual C++
Исходный номер базы знаний: 815662
Сводка
Блок try-catch-finally — это оболочка, которая помещается вокруг любого кода, в котором может возникнуть исключение. Перехват и работа с исключениями — это стандартные задачи программирования.
Блок try-catch-finally состоит из следующих разделов:
- Любой код, который может вызвать исключение, помещается в блок try.
- Если возникает исключение, catch вводится блок, и программа может выполнить соответствующую операцию для восстановления или оповещения пользователя.
- Код в блоке finally всегда выполняется и может выполнять очистку после возникновения исключения. Блок finally необязателен.
В этой статье рассматриваются следующие пространства имен библиотеки классов Microsoft платформа .NET Framework: System.IO и System.Security .
Перехват исключений в Visual C++ .NET
- Запустите Visual Studio .NET.
- В меню Файл выберите пункт Создать и затем пункт Проект.
- В Visual C++ щелкните Visual C++ в разделе Типы проектов, а затем выберите консольное приложение CLR в разделе Шаблоны.
- В поле Имя введите Q815662 и нажмите кнопку ОК.
- Замените весь код в окне кода Q815662.cpp следующим кодом. Код объявляет и инициализирует три переменные. Инициализация k вызывает ошибку.
#include "stdafx.h" #using #include using namespace System; void _tmain(void) < Console::WriteLine("We're going to divide 10 by 0 and see what happens. "); Console::WriteLine(); int i = 10; int j = 0; int k = i/j; //Error on this line. >
#include "stdafx.h" #using #include using namespace System; void _tmain(void) < try < Console::WriteLine("We're going to divide 10 by 0 and see what happens. "); Console::WriteLine(); int i = 10; int j = 0; int k = i/j; //Error on this line. >catch(. ) < Console::WriteLine("An error occurred."); >>
Примечание. Сообщение об ошибке catch из блока отображается вместо сообщения об ошибке системного исключения.
This statement is always printed.
Замените код в окне кода Q815662.cpp следующим кодом:
#include "stdafx.h" #using #include using namespace System; void _tmain(void) < try < Console::WriteLine("We're going to divide 10 by 0 and see what happens. "); Console::WriteLine(); int i = 10; int j = 0; int k = i/j; //Error on this line. >catch(. ) < Console::WriteLine("An error occurred."); >__finally //This section is performed regardless of the above processing. < Console::WriteLine(); Console::WriteLine("This statement is always printed"); >>
#include "stdafx.h" #using #include using namespace System; using namespace System::Reflection; void _tmain(void) < try < Console::WriteLine("We're going to divide 10 by 0 and see what happens. "); Console::WriteLine(); int i = 10; int j = 0; int k = i/j; //Error on this line. >catch(Exception *e) < Console::WriteLine("An error occurred."); Console::WriteLine(e->Message); // Print the error message. Console::WriteLine(e->StackTrace); //String that contains the stack trace for this exception. > __finally //This section is performed regardless of the above processing. < Console::WriteLine(); Console::WriteLine("This statement is always printed"); >Console::ReadLine(); >
#include "stdafx.h" #using #include using namespace System; using namespace System::IO; using namespace System::Security; void _tmain(void) < try < File::Create("c:\\temp\\testapp.txt"); //Can fail for a number of resons >// This error may occur if the temp folder does not exist. catch(IOException *ioe) < Console::WriteLine("An IOException exception occurred!"); Console::WriteLine(ioe->ToString()); > // You do not have the appropriate permission to take this action. catch(SecurityException *se) < Console::WriteLine("An SecurityException exception occur") >// Catch all exceptions catch(Exception *e) < Console::WriteLine(e->ToString()); > >
Обратная связь
Были ли сведения на этой странице полезными?
Исключения
В процессе работы программы могут возникать различные ошибки. Например, при передаче файла по сети оборвется сетевое подключение или будут введены некорректные и недопустимые данные, которые вызовут падение программы. Такие ошибки еще называются исключениями. Исключение представлякт временный объект любого типа, который используется для сигнализации об ошибке. Цель объекта-исключения состоит в том, чтобы передать информацию из точки, в которой произошла ошибка, в код, который должен ее обработать. Если исключение не обработано, то при его возникновении программа прекращает свою работу.
Например, в следующей программе происходит деление чисел:
#include double divide(int a, int b) < return a / b; >int main() < int x; int y<>; double z
Эта программа успешно скомпилируется, но при ее выполнении возникнет ошибка, поскольку в коде производится деление на ноль, после чего программа аварийно завершится.
С одной стороны, мы можем в функции divide определить проверку и выполнять деление, если параметр b не равен 0. Однако нам в любом случае надо возвращать из функции divide некоторый результат — некоторое число. То есть мы не можем просто написать:
double divide(int a, int b) < if (b) return a / b; else std::cout
И в этом случае нам надо известить систему о возникшей ошибке. Для этого используется оператор throw .
Оператор throw генерирует исключение. Через оператор throw можно передать информацию об ошибке. Например, функция divide могла бы выглядеть следующим образом:
double divide(int a, int b) < if (b) return a / b; throw "Division by zero!"; >
То есть если параметр b равен 0, то генерируем исключение.
Но это исключение еще надо обработать в коде, где будет вызываться функция divide. Для обработки исключений применяется конструкция try. catch . Она имеет следующую форму:
try < инструкции, которые могут вызвать исключение >catch(объявление_исключения)
В блок кода после ключевого слова try помещается код, который потенциально может сгенерировать исключение.
После ключевого слова catch в скобках идет параметр, который передает информацию об исключении. Затем в блоке производится собственно обработка исключения.
Так изменим весь код следующим образом:
#include double divide(int a, int b) < if (b) return a / b; throw "Division by zero!"; >int main() < int x; int y<>; try < double z Код, который потенциально может сгенерировать исключение — вызов функции divide помещается в блок try. В блоке catch идет обработка исключения. Причем многоточие в скобках после оператора catch ( catch(. ) ) позволяет обработать любое исключение. В итоге когда выполнение программы дойдет до строки При выполнении этой строки будет сгенерировано исключение, поэтому последующие инструкции из блока try выполняться не будут, а управление перейдет в блок catch, в котором на консоль просто выводится сообщение об ошибке. После выполнения блока catch программа аварийно не завершится, а продолжит свою работу, выполняя операторы после блока catch: Однако в данном случае мы только знаем, что произошла какая-то ошибка, а какая именно, неизвестно. Поэтому через параметр в блоке catch мы можем получить то сообщение, которое передается оператору throw : #include >iostream < double divide(int a, int b) < if (b) return a / b; throw "Division by zero!"; >int main() < int x; int y<>; try < double z С помощью параметра const char* error_message получаем сообщение, которое предано оператору throw, и выводим это сообщение на консоль. Почему здесь мы получаем сообщение об ошибке в виде типа const char* ? Потому что после оператора throw идет строковый литерал, который представляет как раз тип const char* . И в этом случае консольный вывод будет выглядеть следующим образом: Таким образом, мы можем узнать суть возникшего исключения. Подобным образом мы можем передавать информацию об исключении через любые типы, например, std::string: Тогда в блоке catch мы можем получить эту информацию в виде объекта std::string : catch (std::string error_message) Если же исключение не обработано, то вызывается функция std::terminate() (из модуля стандартной библиотеки C++), которая, в свою очередь, по умолчанию вызывает другую функцию — std::abort() (из ), которая собственно и завершает программу. Существует очень много функций и в стандартной библиотеке С++, и в каких-то сторонних библиотеках. И может возникнуть вопрос, какие из них вызывать в конструкции try-catch, чтобы не столкнуться с необработанным исключением и аварийным завершением программы. В этом случае может помочь прежде всего документация по функции (при ее наличии). Другой сигнал — ключевое слово noexcept , которое при использовании в заголовке функции указывает, что эта функция никогда не будет генерировать исключения. Например: Здесь указываем, что функция print() никогда не вызовет исключение. Таким образом, встретив функцию с подобным ключевым словом, можно ожидать, что она не вызовет исключения. И соответственно нет необходимости помещать ее вызов в конструкцию try-catch. При обработке исключения стоит помнить, что при передаче объекта оператору throw блок catch получает копию этого объекта. И эта копия существует только в пределах блока catch. Для значений примитивных типов, например, int , копирование значения может не влиять на производительность программы. Однако при передаче объектов классов издержки могут выше. Поэтому в этом случае объекты обычно передаются по ссылке, например: #include double divide(int a, int b) < if (b) return a / b; throw std::string; > int main() < int x; int y<>; try < double z Мы можем генерировать и обрабатывать несколько разных исключительных ситуаций. Допустим, нам надо, чтобы при делении делитель (второе число) был не больше, чем делимое (первое число): В функции divide в зависимости от значения числа b оператору throw передаем либо число: либо строковый литерал: Для тестирования функции divide определена другая функция — test, где вызов функции divide() помещен в конструкцию try..catch . Поскольку при генерации исключения мы можем получать ошибку в виде двух типов — int (если b равно 0) и const char* (если b больше a), то для обработки каждого типа исключений определены два разных блока catch: catch (int code) < std::cout catch (const char* error_message)
В функции main вызываем функцию test, передавая в нее различные числа. При вызове: число b не равно 0 и меньше a, поэтому никаких исключений не возникает, блок try срабатывает до конца, и функция завершает свое выполнение. При втором вызове число b равно 0, поэтому генерируется исключение, а в качестве объекта исключения передается число 0. Поэтому при возникновении исключения программа выберет тот блок catch, где обрабатывается исключения типа int: catch (int code) При третьем вызове число b больше a, поэтому объект исключения будет представлять строковый литерал или const char* . Поэтому при возникновении исключения программа выберет блок catch, где обрабатывается исключения типа const char*: catch (const char* error_message) Таким образом, в данном случае мы получим следующий консольный вывод: Может быть ситуация, когда генерируется исключение внутри конструкции try-catch , и даже есть блок catch для обработки исключений, однако он обрабатывает другие типы исключений: Здесь нет блока catch для обработки исключения типа int . Поэтому при генерации исключения: Программа не найдет нужный блок catch для обработки исключения, и программа аварийно завершит свое выполнение. Стоит отметить, что, если в блоке try создаются некоторые объекты, то при возникновении исключения у них вызываются деструкторы. Например: В классе Person определяет деструктор, который выводит сообщение на консоль. В функции print просто генерируем исключение. В функции main в блоке try создаем один объект Person и вызываем у него функцию print, что естественно приведет к генерарции исключения и переходу управления программы в блок catch . И если мы посмотрим на консольный вывод то мы увидим, что прежде чем начнется обработка исключения в блоке catch, будет вызван деструктор объекта Person. Хорошо спроектированное приложение обрабатывает исключения и ошибки, чтобы предотвратить сбои приложения. В этой статье описаны рекомендации по обработке и созданию исключений. Используйте try / catch блоки вокруг кода, который может создать исключение, и код может восстановиться после этого исключения. В блоках catch следует всегда упорядочивать исключения от более производных к менее производным. Все исключения являются производными от Exception класса. Более производные исключения не обрабатываются предложением catch, предшествующим предложению catch для базового класса исключений. Если код не может восстановиться из исключения, не перехватывайте это исключение. Включите методы выше по стеку вызовов для восстановления по мере возможности. Очистка ресурсов, выделенных с помощью using инструкций или finally блоков. Рекомендуется использовать инструкции using для автоматической очистки ресурсов при возникновении исключений. Используйте блоки finally , чтобы очистить ресурсы, которые не реализуют IDisposable. Код в предложении finally выполняется почти всегда — даже при возникновении исключений. Для условий, которые могут возникнуть, но способны вызвать исключение, рекомендуется реализовать обработку таким способом, который позволит избежать исключения. Например, если вы попытаетесь закрыть подключение, которое уже закрыто, вы получите InvalidOperationException . Этого можно избежать, используя оператор if для проверки состояния подключения перед попыткой закрыть его. Если вы не проверка состояние подключения перед закрытием InvalidOperationException , можно поймать исключение. Выбор конкретного способа зависит от того, насколько часто ожидается возникновение данного события. Класс может предоставлять методы и свойства, позволяющие избежать вызова, способного выдать исключение. Например, класс FileStream содержит методы, позволяющие определить, достигнут ли конец файла. Эти методы можно использовать для предотвращения исключения, которое возникает при чтении в конце файла. В следующем примере показано, как считывать конец файла без активации исключения: Другим способом избежать исключений является возврат null (или по умолчанию) для большинства распространенных случаев ошибок вместо того, чтобы вызвать исключение. Распространенный случай ошибки можно рассматривать как обычный поток управления. Возвращая значение NULL (или значение по умолчанию) в таких случаях, можно уменьшить влияние на производительность приложения. Для типов значений, следует ли использовать Nullable или по умолчанию в качестве индикатора ошибки, что следует учитывать для приложения. При использовании Nullable default принимает значение null , а не Guid.Empty . Иногда добавление Nullable может сделать его более понятным, если значение присутствует или отсутствует. В других случаях добавление Nullable может создавать дополнительные случаи для проверка, которые не нужны и служат только для создания потенциальных источников ошибок. Исключения гарантируют, что сбои не замечены, так как вызывающий код не проверка возвращаемого кода. Создавайте новый класс исключений, только если предопределенное исключение не подходит. Например: Если требуется пользовательское исключение, присвойте ему соответствующее имя и сделайте его производным от класса Exception. Например: При создании собственных классов исключений можно использовать по меньшей мере три общих конструктора: конструктор без параметров, конструктор, принимающий строковое сообщение, и конструктор, принимающий строковое сообщение и внутреннее исключение. При создании определяемых пользователем исключений убедитесь, что метаданные исключений доступны для кода, выполняющегося удаленно. Например, в реализациях .NET, поддерживающих домены приложений, исключения могут возникать в доменах приложений. Предположим, домен приложения A создает домен приложения B, который выполняет код, который создает исключение. Чтобы домен приложения A правильно перехватывал и обрабатывал исключение, он должен иметь возможность найти сборку, содержащую исключение, созданное доменом приложения B. Если домен приложения B создает исключение, содержащееся в сборке под его базой приложения, но не в базе приложения A домена приложения, домен приложения A не сможет найти исключение, а среда CLR вызовет FileNotFoundException исключение. Чтобы избежать этой ситуации, можно развернуть сборку, содержащую сведения об исключении двумя способами: Составляйте понятные предложения, указывая в конце знаки препинания. Каждое предложение в строке, назначенной свойству Exception.Message, должно заканчиваться точкой. Например, «Таблица журнала переполнена». Сообщение об ошибке, которое видит пользователь, является производным от Exception.Message свойства создаваемого исключения, а не от имени класса исключений. Как правило, значение присваивается Exception.Message свойству путем передачи строки message сообщения в аргумент конструктора исключений. Для локализованных приложений необходимо предоставить строку локализованного сообщения для всех исключений, которые может создавать приложение. Используйте файлы ресурсов для предоставления локализованных сообщений об ошибках. Сведения о локализации приложений и извлечении локализованных строк см. в следующих статьях: Дополнительные сведения (кроме строки настраиваемого сообщения) включайте в исключение только в случаях, когда в соответствии со сценарием программирования такие дополнительные сведения могут оказаться полезными. Например, исключение FileNotFoundException предоставляет свойство FileName. Трассировка стека начинается в операторе, породившем исключение, и завершается оператором catch , перехватывающим это исключение. Обычно класс создает одно и то же исключение из разных мест в его реализации. Чтобы избежать повторения кода, используйте вспомогательные методы, создающие исключение и затем возвращающие его. Например: В некоторых случаях для создания исключения лучше воспользоваться конструктором исключений. В качестве примера можно привести класс глобальных исключений, например ArgumentException. Вызывающие объекты должны предполагать, что при создании исключения из метода не возникают побочные эффекты. Например, если у вас есть код, который передает деньги, списывая их с одного счета и внося на другой, и при начислении средств возникает исключение, списание средств применяться не должно. Предыдущий метод не создает никаких исключений напрямую. Однако необходимо написать метод, чтобы отмена вывода была отменена, если операция депозита завершается сбоем. Один из способов обработки в этой ситуации заключается в перехвате всех исключений, выданных транзакцией начисления средств, и откате транзакции списания средств. В этом примере показано использование throw повторного изменения исходного исключения, что упрощает для вызывающих абонентов видеть реальную причину проблемы без необходимости проверки InnerException свойства. Альтернативой является создание нового исключения и включение исходного исключения в качестве внутреннего исключения. Чтобы записать исключение и сохранить его вызовы, чтобы иметь возможность повторно выполнить его повторно, используйте System.Runtime.ExceptionServices.ExceptionDispatchInfo класс. Этот класс предоставляет следующие методы и свойства (среди прочего): В следующем примере показано, как ExceptionDispatchInfo можно использовать класс и как выглядеть выходные данные. Если файл в примере кода не существует, создается следующий результат: Совместная работа с нами на GitHub Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников. Иногда при выполнении программы возникают ошибки, которые трудно предусмотреть или предвидеть, а иногда и вовсе невозможно. Например, при передачи файла по сети может неожиданно оборваться сетевое подключение. такие ситуации называются исключениями . Язык C# предоставляет разработчикам возможности для обработки таких ситуаций. Для этого в C# предназначена конструкция try. catch. finally . try < >catch < >finally При использовании блока try. catch..finally вначале выполняются все инструкции в блоке try . Если в этом блоке не возникло исключений, то после его выполнения начинает выполняться блок finally . И затем конструкция try..catch..finally завершает свою работу. Если же в блоке try вдруг возникает исключение, то обычный порядок выполнения останавливается, и среда CLR начинает искать блок catch , который может обработать данное исключение. Если нужный блок catch найден, то он выполняется, и после его завершения выполняется блок finally. Если нужный блок catch не найден, то при возникновении исключения программа аварийно завершает свое выполнение. Рассмотрим следующий пример: В данном случае происходит деление числа на 0, что приведет к генерации исключения. И при запуске приложения в режиме отладки мы увидим в Visual Studio окошко, которое информирует об исключении: В этом окошке мы видим, что возникло исключение, которое представляет тип System.DivideByZeroException , то есть попытка деления на ноль. С помощью пункта View Details можно посмотреть более детальную информацию об исключении. И в этом случае единственное, что нам остается, это завершить выполнение программы. Чтобы избежать подобного аварийного завершения программы, следует использовать для обработки исключений конструкцию try. catch. finally . Так, перепишем пример следующим образом: В данном случае у нас опять же возникнет исключение в блоке try, так как мы пытаемся разделить на ноль. И дойдя до строки выполнение программы остановится. CLR найдет блок catch и передаст управление этому блоку. После блока catch будет выполняться блок finally. Таким образом, программа по-прежнему не будет выполнять деление на ноль и соответственно не будет выводить результат этого деления, но теперь она не будет аварийно завершаться, а исключение будет обрабатываться в блоке catch. Следует отметить, что в этой конструкции обязателен блок try . При наличии блока catch мы можем опустить блок finally: try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > catch И, наоборот, при наличии блока finally мы можем опустить блок catch и не обрабатывать исключение: try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > finally Однако, хотя с точки зрения синтаксиса C# такая конструкция вполне корректна, тем не менее, поскольку CLR не сможет найти нужный блок catch, то исключение не будет обработано, и программа аварийно завершится. Ряд исключительных ситуаций может быть предвиден разработчиком. Например, пусть в программе есть метод, который принимает строку, конвертирует ее в число и вычисляет квадрат этого числа: Если пользователь передаст в метод не число, а строку, которая содежит нецифровые символы, то программа выпадет в ошибку. С одной стороны, здесь как раз та ситуация, когда можно применить блок try..catch , чтобы обработать возможную ошибку. Однако гораздо оптимальнее было бы проверить допустимость преобразования: Метод int.TryParse() возвращает true , если преобразование можно осуществить, и false — если нельзя. При допустимости преобразования переменная x будет содержать введенное число. Так, не используя try. catch можно обработать возможную исключительную ситуацию. С точки зрения производительности использование блоков try..catch более накладно, чем применение условных конструкций. Поэтому по возможности вместо try..catch лучше использовать условные конструкции на проверку исключительных ситуаций. Помощь сайту Контакты для связи: metanit22@mail.ru Copyright © metanit.com, 2024. Все права защищены.double z
Error! The End.
Division by zero! The End.
throw std::string;
void print(int argument) noexcept;
Создание объекта исключения
Обработка и генерация разных типов исключений
#include double divide(int a, int b) < if(!b) // если b == 0 < throw 0; >if(b > a) < throw "The second number is greater than the first one"; >return a / b; > void test(int a, int b) < try < double result
throw 0;
throw "The second number is greater than the first one";
test(100, 20); // 5
test(100, 0); // Error code: 0
test(100, 1000); // The second number is greater than the first one
5 Error code: 0 The second number is greater than the first one
void test(int a, int b) < try < double result
throw 0;
try-catch и деструкторы
#include class Person < public: Person(std::string name) :name< name > < std::cout ~Person() < std::cout void print() < throw "Print Error"; >private: std::string name; >; int main() < try < Person tom< "Tom" >; tom.print(); // Здесь генерируется ошибка > catch (const char* error) < std::cerr >
Person Tom created Person Tom deleted Print Error
Лучшие методики обработки исключений
Использование блоков try/catch/finally для восстановления после ошибок или высвобождения ресурсов
Обработка общих условий без выдачи исключений
if (conn->State != ConnectionState::Closed) < conn->Close(); >
if (conn.State != ConnectionState.Closed)
If conn.State <> ConnectionState.Closed Then conn.Close() End IF
try < conn->Close(); > catch (InvalidOperationException^ ex) < Console::WriteLine(ex->GetType()->FullName); Console::WriteLine(ex->Message); >
try < conn.Close(); >catch (InvalidOperationException ex)
Try conn.Close() Catch ex As InvalidOperationException Console.WriteLine(ex.GetType().FullName) Console.WriteLine(ex.Message) End Try
Устранение исключений при разработке классов
class FileRead < public: void ReadAll(FileStream^ fileToRead) < // This if statement is optional // as it is very unlikely that // the stream would ever be null. if (fileToRead == nullptr) < throw gcnew System::ArgumentNullException(); >int b; // Set the stream position to the beginning of the file. fileToRead->Seek(0, SeekOrigin::Begin); // Read each byte to the end of the file. for (int i = 0; i < fileToRead->Length; i++) < b = fileToRead->ReadByte(); Console::Write(b.ToString()); // Or do something else with the byte. > > >;
class FileRead < public void ReadAll(FileStream fileToRead) < // This if statement is optional // as it is very unlikely that // the stream would ever be null. if (fileToRead == null) < throw new ArgumentNullException(); >int b; // Set the stream position to the beginning of the file. fileToRead.Seek(0, SeekOrigin.Begin); // Read each byte to the end of the file. for (int i = 0; i < fileToRead.Length; i++) < b = fileToRead.ReadByte(); Console.Write(b.ToString()); // Or do something else with the byte. >> >
Class FileRead Public Sub ReadAll(fileToRead As FileStream) ' This if statement is optional ' as it is very unlikely that ' the stream would ever be null. If fileToRead Is Nothing Then Throw New System.ArgumentNullException() End If Dim b As Integer ' Set the stream position to the beginning of the file. fileToRead.Seek(0, SeekOrigin.Begin) ' Read each byte to the end of the file. For i As Integer = 0 To fileToRead.Length - 1 b = fileToRead.ReadByte() Console.Write(b.ToString()) ' Or do something else with the byte. Next i End Sub End Class
Выдача исключений вместо возврата кода ошибки
Использование предопределенных типов исключений .NET
Завершайте имена классов исключений словом Exception
public ref class MyFileNotFoundException : public Exception < >;
public class MyFileNotFoundException : Exception
Public Class MyFileNotFoundException Inherits Exception End Class
Включение трех конструкторов в пользовательские классы исключений
Обеспечение доступности данных об исключении при удаленном выполнении кода
Использование грамматически правильных сообщений об ошибке
Включение локализованной строки сообщения в каждое исключение
Предоставление дополнительных свойств в пользовательских исключениях по мере необходимости
Размещение операторов throw для удобной трассировки стека
Использование методов построителя исключений
ref class FileReader < private: String^ fileName; public: FileReader(String^ path) < fileName = path; >array^ Read(int bytes) < array^ results = FileUtils::ReadFromFile(fileName, bytes); if (results == nullptr) < throw NewFileIOException(); >return results; > FileReaderException^ NewFileIOException() < String^ description = "My NewFileIOException Description"; return gcnew FileReaderException(description); >>;
class FileReader < private string fileName; public FileReader(string path) < fileName = path; >public byte[] Read(int bytes) < byte[] results = FileUtils.ReadFromFile(fileName, bytes); if (results == null) < throw NewFileIOException(); >return results; > FileReaderException NewFileIOException() < string description = "My NewFileIOException Description"; return new FileReaderException(description); >>
Class FileReader Private fileName As String Public Sub New(path As String) fileName = path End Sub Public Function Read(bytes As Integer) As Byte() Dim results() As Byte = FileUtils.ReadFromFile(fileName, bytes) If results Is Nothing Throw NewFileIOException() End If Return results End Function Function NewFileIOException() As FileReaderException Dim description As String = "My NewFileIOException Description" Return New FileReaderException(description) End Function End Class
Восстановление состояния, если методы не выполняются из-за исключения
public void TransferFunds(Account from, Account to, decimal amount) < from.Withdrawal(amount); // If the deposit fails, the withdrawal shouldn't remain in effect. to.Deposit(amount); >
Public Sub TransferFunds(from As Account, [to] As Account, amount As Decimal) from.Withdrawal(amount) ' If the deposit fails, the withdrawal shouldn't remain in effect. [to].Deposit(amount) End Sub
private static void TransferFunds(Account from, Account to, decimal amount) < string withdrawalTrxID = from.Withdrawal(amount); try < to.Deposit(amount); >catch < from.RollbackTransaction(withdrawalTrxID); throw; >>
Private Shared Sub TransferFunds(from As Account, [to] As Account, amount As Decimal) Dim withdrawalTrxID As String = from.Withdrawal(amount) Try [to].Deposit(amount) Catch from.RollbackTransaction(withdrawalTrxID) Throw End Try End Sub
catch (Exception ex) < from.RollbackTransaction(withdrawalTrxID); throw new TransferFundsException("Withdrawal failed.", innerException: ex) < From = from, To = to, Amount = amount >; >
Catch ex As Exception from.RollbackTransaction(withdrawalTrxID) Throw New TransferFundsException("Withdrawal failed.", innerException:=ex) With < .From = from, .[To] = [to], .Amount = amount >End Try
Запись исключений для повторного восстановления позже
ExceptionDispatchInfo? edi = null; try < var txt = File.ReadAllText(@"C:\temp\file.txt"); >catch (FileNotFoundException e) < edi = ExceptionDispatchInfo.Capture(e); >// . Console.WriteLine("I was here."); if (edi is not null) edi.Throw();
I was here. Unhandled exception. System.IO.FileNotFoundException: Could not find file 'C:\temp\file.txt'. File name: 'C:\temp\file.txt' at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options) at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode) at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode) at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode) at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize) at System.IO.File.ReadAllText(String path, Encoding encoding) at Example.ProcessFile.Main() in C:\repos\ConsoleApp1\Program.cs:line 12 --- End of stack trace from previous location --- at Example.ProcessFile.Main() in C:\repos\ConsoleApp1\Program.cs:line 24
См. также
Обработка исключений
int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); Console.WriteLine("Конец программы");
try < int x = 5; int y = x / 0; Console.WriteLine($"Результат: "); > catch < Console.WriteLine("Возникло исключение!"); >finally < Console.WriteLine("Блок finally"); >Console.WriteLine("Конец программы");
int y = x / 0;
Возникло исключение! Блок finally Конец программы
Обработка исключений и условные конструкции
Square("12"); // Квадрат числа 12: 144 Square("ab"); // !Исключение void Square(string data) < int x = int.Parse(data); Console.WriteLine($"Квадрат числа : "); >
Square("12"); // Квадрат числа 12: 144 Square("ab"); // Некорректный ввод void Square(string data) < if (int.TryParse(data, out var x)) < Console.WriteLine($"Квадрат числа : "); > else < Console.WriteLine("Некорректный ввод"); >>
410011174743222
Перевод на карту
Номер карты:
4048415020898850