I need to stop my program when an exception is raised in Python.
How do I implement this?
cHao
84.7k20 gold badges145 silver badges172 bronze badges
asked Jan 13, 2009 at 13:13
3
import sys
try:
print("stuff")
except:
sys.exit(1) # exiting with a non zero value is better for returning from an error
brian d foy
129k31 gold badges203 silver badges586 bronze badges
answered Jan 13, 2009 at 13:16
Loïc WolffLoïc Wolff
3,16625 silver badges26 bronze badges
5
You can stop catching the exception, or — if you need to catch it (to do some custom handling), you can re-raise:
try:
doSomeEvilThing()
except Exception, e:
handleException(e)
raise
Note that typing raise without passing an exception object causes the original traceback to be preserved. Typically it is much better than raise e.
Of course — you can also explicitly call
import sys
sys.exit(exitCodeYouFindAppropriate)
This causes SystemExit exception to be raised, and (unless you catch it somewhere) terminates your application with specified exit code.
answered Jan 13, 2009 at 14:33
AbganAbgan
3,69022 silver badges31 bronze badges
1
If you don’t handle an exception, it will propagate up the call stack up to the interpreter, which will then display a traceback and exit. IOW : you don’t have to do anything to make your script exit when an exception happens.
answered Jan 13, 2009 at 19:52
1
import sys
try:
import feedparser
except:
print "Error: Cannot import feedparser.n"
sys.exit(1)
Here we’re exiting with a status code of 1. It is usually also helpful to output an error message, write to a log, and clean up.
answered Nov 18, 2009 at 22:36
PranabPranab
2,0974 gold badges28 silver badges48 bronze badges
2
As far as I know, if an exception is not caught by your script, it will be interrupted.
answered Jan 13, 2009 at 13:15
KeltiaKeltia
14.5k3 gold badges29 silver badges30 bronze badges
0

В ряде случаев даже самые «стабильные» и надежные программы могут перестать отзываться на какие-либо нажатия мышки/клавиатуры (т.е. попросту зависнуть).
Для решения вопроса, можно, конечно, перезагрузить ПК/ноутбук — но далеко не всегда это удобно (часть данных в др. ПО будет сброшена и не сохранится…).
Логично, что лучше всего закрыть только эту конкретно-зависшую программу. Всем известное сочетание ALT+F4 — далеко не всегда решает проблему, и, собственно, поэтому набросал небольшую заметку с несколькими способами принудительной ликвидации процесса.
Итак…
📌 Кстати!
Если ПК/ноутбук вообще не реагирует ни на одну из кнопок клавиатуры — то скорее всего зависла не только отдельно-взятая программа, но и в целом система.
Если так, то для перезагрузки/выключения устройства — зажмите кнопку питания (Power) на 4-5 сек. (разумеется, все несохраненные данные будут утеряны).
*
Способы закрыть не отвечающую программу
👉 Первый
Итак, самый очевидный и простой вариант — просто кликнуть правой кнопкой мышки по значку зависшей программы на панели задач Windows. После, во всплывшем окне достаточно будет выбрать вариант «закрыть окно».
Закрыть окно
*
👉 Второй
Если зависло полно-экранное приложение и до панели задач вы просто не можете добраться, попробуйте сочетания:
- WIN, или WIN+TAB, или ALT+TAB, или ALT+Enter — чтобы свернуть окно;
- ALT+F4, или ESC, или ALT+Q — для закрытия (выхода) из программы.
ALT+Q / клавиатура
Перечисленные «горячие» сочетания клавиш работают с подавляющем большинством ПО для Windows.
*
👉 Третий
Нажмите сочетание клавиш Ctrl+Shift+Esc (или Ctrl+Alt+Del) для вызова диспетчер задач. Далее во вкладке процессы найдите зависшую программу (процесс), кликните по ней правой кнопкой мыши и в появившемся выберите «Снять задачу». Через 3-5 сек. программа должна быть закрыта.
Ctrl+Shift+Esc или Ctrl+Alt+Del — открыть диспетчер задач
Кстати, если рабочий стол после этого стал отображаться «как-то не так» (или вообще не видно) — перезапустите процесс «Проводник» (или «Explorer» на англ.).
Примечание: также проводник можно перезапустить из командной строки, введя taskkill /F /IM explorer.exe & start explorer и нажав Enter.
Проводник — перезапустить
*
👉 Четвертый
Командная строка — универсальная штука, которая может помочь и с закрытием (ликвидацией) зависших процессов (программ). Кстати, если вы наловчитесь с ее использованием — закрывать зависшие полно-экранные приложения можно будет даже в «слепую» (когда на экране ничего не отображается).
Как это делается:
- сначала нужно открыть 👉 командную строку;
- после ввести tasklist и нажать Enter;
- на экране появится список всех процессов (следует уточнить имя процесса/программы, которую нужно закрыть);
- после ввести taskkill /IM chrome.exe /f и нажать Enter (вместо «chrome.exe» — указывается имя нужного процесса).
Убиваем процесс через командную строку
*
👉 Пятый
Если вышеприведенные варианты не увенчались успехом, можно прибегнуть к утилите Process Hacker (ссылка на SourceForge). Это бесплатное ПО, которое покажет вам все запущенные процессы, их приоритеты, занимаемую память, нагрузку и пр.
Чтобы ликвидировать (закрыть) в нем любую из запущенных программ — нужно просто ее выбрать в списке, затем нажать ПКМ по ее имени и в появившемся окне выбрать «Terminate tree» (см. пример ниже 👇).
Process Hacker 2 — закрыть дерево процессов
Стоит отметить, что Process Hacker закроет сразу всё дерево процессов, связанных с этой программой (чего не делают многие др. программы…).
*
PS
Если у вас часто начала зависать какая-либо программа (еще хуже программы) — обратите внимание на:
- версию ПО (нежелательно использовать различные бета-версии). Проверьте, совместима ли версия ПО с вашей ОС (в помощь: какая версия Windows установлена на моем компьютере);
- обновите драйвера (желательно с офиц. сайта);
- проверьте жесткий диск (если он начал «сыпаться» — подвисания будут идти постоянно);
- прогоните систему с помощью спец. «одноразовых» антивирусных продуктов;
- возможно, вашему приложению не хватает ОЗУ (посмотрите при работе ПО — сколько памяти занято в диспетчере задач).
Кроме этого, рекомендую ознакомиться с тематическими инструкциями (ссылки ниже).
👉 В помощь!
1) Вылетает или зависает игра… Что делать?
2) Зависает ноутбук: что делать? Диагностика и устранение причин зависания
3) Ошибка: Kernel-Power код 41, категория 63. Компьютер перезагружается или зависает
*
На этом пока всё…
Дополнения — всегда приветствуются!
Хорошего дня!
👋
Первая публикация: 24.04.2020
Корректировка: 28.10.2021


Полезный софт:
-
- Видео-Монтаж
Отличное ПО для создания своих первых видеороликов (все действия идут по шагам!).
Видео сделает даже новичок!
-
- Ускоритель компьютера
Программа для очистки Windows от «мусора» (удаляет временные файлы, ускоряет систему, оптимизирует реестр).
|
elsum 0 / 0 / 0 Регистрация: 31.10.2017 Сообщений: 40 |
||||||||
|
1 |
||||||||
|
11.12.2017, 23:39. Показов 2093. Ответов 5 Метки нет (Все метки)
Нужно, что бы после
программа писала «Количество не может быть отрицательным» и завершалась после нажатия любой клавиши, а не продолжала считать дальше. Или можно как-то запросить повторный ввод? Подскажите плиз
0 |
|
no swear 192 / 166 / 82 Регистрация: 01.07.2016 Сообщений: 943 |
||||
|
11.12.2017, 23:47 |
2 |
|||
|
Завершение программы
0 |
|
0 / 0 / 0 Регистрация: 31.10.2017 Сообщений: 40 |
|
|
11.12.2017, 23:50 [ТС] |
3 |
|
А повторный ввод можно задать без закрытия?
0 |
|
Gaveyn 99 / 98 / 11 Регистрация: 12.09.2016 Сообщений: 195 |
||||
|
11.12.2017, 23:56 |
4 |
|||
|
Решениеelsum,
2 |
|
qwertyuserc 0 / 0 / 0 Регистрация: 12.11.2017 Сообщений: 49 |
||||||||
|
12.12.2017, 00:11 |
5 |
|||||||
Если я всё правильно понял,то программа должна выглядеть так. Добавлено через 5 минут
0 |
|
0 / 0 / 0 Регистрация: 31.10.2017 Сообщений: 40 |
|
|
12.12.2017, 00:49 [ТС] |
6 |
|
Gaveyn,
0 |
|
IT_Exp Эксперт 87844 / 49110 / 22898 Регистрация: 17.06.2006 Сообщений: 92,604 |
12.12.2017, 00:49 |
|
6 |
Добавлено 29 мая 2021 в 19:48
Последняя категория инструкций управления порядком выполнения программы, которую мы рассмотрим, – это остановки. Остановка – это инструкция управления порядком выполнения программы, которая завершает программу. В C++ остановки реализованы как функции (а не как ключевые слова), поэтому наши инструкции остановки будут вызовами функций.
Давайте сделаем небольшой экскурс и вспомним, что происходит, когда программа завершается нормально. Когда функция main() завершается (либо достигая конца тела функции, либо с помощью инструкции return), происходит ряд разных вещей.
Во-первых, поскольку мы выходим из функции, все локальные переменные и параметры функции уничтожаются (как обычно).
Затем вызывается специальная функция std::exit() со значением, возвращаемым из main() (код состояния), переданным в качестве аргумента. Так что же такое std::exit()?
Функция std::exit()
std::exit() – это функция, которая вызывает нормальное завершение программы. Нормальное завершение означает, что программа завершилась ожидаемым образом. Обратите внимание, что термин «нормальное завершение» ничего не говорит о том, была ли работа программы успешной (для этого нужен код состояния). Например, предположим, что вы пишете программу, в которой ожидаете, что пользователь введет имя файла для обработки. Если пользователь ввел недопустимое имя файла, ваша программа, вероятно, вернет ненулевой код состояния, чтобы указать на состояние сбоя, но это всё равно будет нормальное завершение.
std::exit() выполняет ряд функций очистки. Сначала уничтожаются объекты со статической продолжительностью хранения. Затем выполняется дополнительная очистка файлов, если использовались какие-либо файлы. Наконец, управление возвращается обратно в ОС, а аргумент, переданный в std::exit(), используется в качестве кода состояния.
Явный вызов std::exit()
Хотя std::exit() при завершении функции main() вызывается неявно, она также может быть вызвана явно, чтобы остановить программу до того момента, как она завершится нормально. Когда std::exit() вызывается таким образом, вам нужно будет включить заголовок cstdlib.
Вот пример явного использования std::exit():
#include <cstdlib> // для std::exit()
#include <iostream>
void cleanup()
{
// здесь идет код для выполнения любой необходимой очистки
std::cout << "cleanup!n";
}
int main()
{
std::cout << 1 << 'n';
cleanup();
std::exit(0); // завершаем работу и возвращаем операционной системе код состояния 0
// следующие инструкции никогда не выполняются
std::cout << 2 << 'n';
return 0;
}
Эта программа печатает:
1
cleanup!
Обратите внимание, что инструкции после вызова std::exit() никогда не выполняются, потому что программа уже завершена.
Хотя в приведенной выше программе мы вызываем std::exit() из функции main(), std::exit() можно вызвать из любой функции для завершения программы в необходимой точке.
Одно важное замечание о явном вызове std::exit(): std::exit() не очищает никакие локальные переменные (ни в текущей функции, ни в функциях вверх по стеку вызовов). По этой причине обычно лучше избегать вызова std::exit().
Предупреждение
Функция std::exit() не очищает локальные переменные в текущей функции и в функциях выше по стеку вызовов.
std::atexit
Поскольку std::exit() завершает программу немедленно, вы можете перед завершением выполнить какую-либо очистку вручную (в приведенном выше примере мы вручную вызывали функцию cleanup()). Поэтому программисту необходимо не забывать вручную вызывать функцию очистки перед каждым вызовом exit().
Чтобы помочь в этом, C++ предлагает функцию std::atexit(), которая позволяет вам указать функцию, которая будет автоматически вызываться при завершении программы через std::exit().
#include <cstdlib> // для std::exit()
#include <iostream>
void cleanup()
{
// здесь идет код для выполнения любой необходимой очистки
std::cout << "cleanup!n";
}
int main()
{
std::atexit(cleanup); // регистрируем cleanup() для автоматического
// вызова при вызове std::exit()
std::cout << 1 << 'n';
std::exit(0); // завершаем работу и возвращаем операционной системе код состояния 0
// следующие инструкции никогда не выполняются
std::cout << 2 << 'n';
return 0;
}
Эта программа имеет тот же вывод, что и предыдущий пример:
1
cleanup!
Так зачем вам это делать? Это позволяет вам указать функцию очистки в одном месте (возможно, в main), а затем не беспокоиться о том, чтобы не забыть вызвать эту функцию явно перед вызовом std::exit().
Несколько замечаний о std::atexit() и функции очистки: во-первых, поскольку std::exit() вызывается неявно при завершении main(), если программа завершается таким образом, это вызовет любые функции, зарегистрированные std::atexit(). Во-вторых, регистрируемая функция не должна принимать никаких параметров и должна не иметь возвращаемого значения. Наконец, с помощью std::atexit() вы можете зарегистрировать несколько функций очистки, если хотите, и они будут вызываться в порядке, обратном порядку регистрации (последняя зарегистрированная будет вызываться первой).
Для продвинутых читателей
В многопоточных программах вызов std::exit() может привести к сбою вашей программы (поскольку поток, вызывающий std::exit(), будет очищать статические объекты, к которым могут обращаться другие потоки). По этой причине в C++ появилась еще одна пара функций, которые работают аналогично std::exit() и std::atexit(), – std::quick_exit() и std::at_quick_exit(). std::quick_exit() завершает программу нормально, но не очищает статические объекты и может выполнять или не выполнять другие типы очистки. std::at_quick_exit() выполняет ту же роль, что и std::atexit() для программ, завершаемых с помощью std::quick_exit().
std::abort и std::terminate
C++ также содержит две другие функции, связанные с остановкой.
Функция std::abort() вызывает аварийное завершение вашей программы. Аварийное завершение означает, что в программе произошла какая-то необычная ошибка времени выполнения, и программа не может продолжать работу. Например, к аварийному завершению попытка разделить на 0 приведет. std::abort() не выполняет никакой очистки.
#include <cstdlib> // for std::abort()
#include <iostream>
int main()
{
std::cout << 1 << 'n';
std::abort();
// следующие инструкции никогда не выполняются
std::cout << 2 << 'n';
return 0;
}
Случаи, когда std::abort вызывается неявно, мы увидим в этой главе позже (7.17 – assert и static_assert).
Функция std::terminate() обычно используется вместе с исключениями (мы рассмотрим исключения в следующей главе). Хотя std::terminate можно вызвать явно, она чаще вызывается неявно, когда исключение не обрабатывается (и в некоторых других случаях, связанных с исключениями). По умолчанию std::terminate() вызывает std::abort().
Когда следует использовать остановки?
Короткий ответ: «почти никогда». В C++ уничтожение локальных объектов является важной частью C++ (особенно когда мы дойдем до классов), и ни одна из вышеупомянутых функций не очищает локальные переменные. Исключения – лучший и безопасный механизм обработки ошибок.
Лучшая практика
Используйте остановки только в том случае, если нет безопасного способа нормально вернуться из функции main. Если вы не отключили исключения, используйте их для безопасной обработки ошибок.
Теги
C++ / CppLearnCppstd::abort()std::at_quick_exit()std::atexit()std::exit()std::quick_exit()std::terminate()STL / Standard Template Library / Стандартная библиотека шаблоновДля начинающихОбучениеПрограммирование
Содержание
- Исключения (Exceptions) и инструкция try
- Оговорка catch
- Блок finally
- Инструкция using
- Выбрасывание исключений
- Основные свойства System.Exception
- Основные типы исключений
- Директивы препроцессора
- Pragma Warning
- Атрибут Conditional
- Классы Debug и Trace
- TraceListener
- Fail и Assert
Исключения, их обработка, и некоторые другие моменты, связанные с ошибками в приложении на C#.
Исключения (Exceptions) и инструкция try
Инструкция try отмечает блок кода как объект для обработки ошибок или очистки. После блока try обязательно должен идти либо блок catch, либо блок finally, либо они оба. Блок catch выполняется, когда внутри блока try возникает ошибка. Блок finally выполняется после того, как прекращает выполнять блок try (или, если присутствует, блок catch), независимо от того, выполнился ли он до конца или был прерван ошибкой, что позволяет выполнить так называемый код очистки.
Блок catch имеет доступ к объекту исключения (Exception), который содержит информацию об ошибке. Блок catch позволяет обработать исключительную ситуацию и как-либо скорректировать ошибку или выбросить новое исключение. Повторное выбрасывание исключения в блоке catch обычно применяется с целью логирования ошибок или чтобы выбросить новое, более специфическое исключение.
Блок finally добавляет в программу прогнозируемость, позволяя выполнить определенный код при любых обстоятельствах. Это может быть полезно для выполнения операций очистки, например, закрытия сетевого подключения и т.д.
В целом конструкция try выглядит следующим образом:
|
try { ... // в пределах этого блока может быть выброшено исключение } catch (ExceptionA ex) { ... // обработчик исключений типа ExceptionA } catch (ExceptionB ex) { ... // обработчик исключений типа ExceptionB } finally { ... // код очистки } |
Например, следующий код выбросит ошибку DivideByZeroException (поскольку делить на ноль нельзя) и наша программа завершить досрочно:
|
int x = 3, y = 0; Console.WriteLine (x / y); |
Чтобы этого избежать можно использовать конструкцию try:
|
try { int x = 3, y = 0; Console.WriteLine (x / y); } catch (DivideByZeroException ex) { Console.Write («y cannot be zero. «); } // выполнение программы продолжится отсюда |
Обработка исключений довольно ресурсоёмкая операция, поэтому на практике для таких случаев как в примере ее лучше не использовать (лучше непосредственно перед делением проверить делить на равенство нулю).
Когда выбрасывается исключение, CLR проверяет выброшено ли оно непосредственно внутри блока try, который может обработать данное исключение. Если да, выполнение переходит в соответствующий блок catch. Если блок catch успешно завершается, выполнение переходит к следующей после блока try инструкции (если имеется блок finally, то сначала выполняется он). Если же исключение выброшено не внутри блока try или конструкция try не содержит соответствующего блока catch, выполнение переходит в точку вызова метода (при этом сначала выполняется блок finally), и проверка повторяется снова.
Если не одна функция в стэке вызовов не способна обработать исключение, ошибка выводиться пользователю и программа завершается досрочно.
Оговорка catch
В оговорке catch указывается какой тип исключения она должна перехватывать. Это может быть либо System.Exception, либо его производный класс. Перехватывая непосредственно System.Exception, мы перехватим все возможные ошибки. Это может быть полезно в нескольких случаях:
- программа потенциально должна и может продолжить работать несмотря на ошибки любых типов
- исключение будет выброшено повторно в блоке
catch, например, после логирования ошибок - блок
catchявляется последним в очереди, способным предотвратить аварийное завершение программы
Однако обычно перехватываются исключения более специфического типа, чтобы избежать ситуации, когда обработчику ошибки придется иметь дело с исключением, для которого он не предназначен (например, OutOfMemoryException).
Можно обработать несколько типов исключений с помощью нескольких оговорок catch:
|
try { DoSomething(); } catch (IndexOutOfRangeException ex) { ... } catch (FormatException ex) { ... } catch (OverflowException ex) { ... } |
Каждая оговорка способна обработать только то исключение, которое точно совпадает с ее типом. Для одного выброшенного исключения может быть выполнена только одна оговорка catch. Обрабатываются блоки catch в том порядке, в котором они идут в коде. В этой связи более специфические исключения должны перехватываться раньше чем более общие.
Исключение может быть перехвачено и без указания переменной, если не нужен доступ к ее членам:
|
catch (StackOverflowException) // без переменной { ... } |
Более того, в оговорке catch можно опустить и переменную и тип исключения — такая оговрка будет перехватывать все исключения:
Блок finally
Блок finally выполняется всегда, независимо от того выброшено исключение или нет. Блок finally обычно содержит код очистки.
Блок finally выполняется в следующих случаях:
- после завершения блока
catch - если выполнение блока
tryпрервано jump-инструкциями:return,gotoи т.д. - после выполнения блока
tryполностью, если исключений так и не было выброшено
Блок finally делает программу более прогнозируемой. Например, в следующем примере открываемый файл в итоге всегда будет закрыт, независимо от того, завершиться ли блок try без ошибок, или будет прерван выброшенным исключением, или сработает инструкция return если файл окажется пустым:
|
static void ReadFile() { StreamReader reader = null; try { reader = File.OpenText («file.txt»); if (reader.EndOfStream) return; Console.WriteLine (reader.ReadToEnd()); } finally { if (reader != null) reader.Dispose(); } } |
В пример для закрытия файла вызывается метод Dispose. Использование этого метода внутри блока finally является стандартной практикой. C# даже позволяет заменить всю конструкцию инструкцией using.
Инструкция using
Многие классы инкапсулируют неуправляемые ресурсы, такие как дескриптор файла, соединение с базой данных и т.д. Эти классы реализуют интерфейс System.IDisposable, который содержит единственный метод без параметров Dispose, освобождающий соответствующие машинные ресурсы. Инструкция using предусматривает удобный синтаксис вызова метода Dispose для объектов реализующих IDisposable внутри блока finally:
|
using (StreamReader reader = File.OpenText («file.txt»)) { ... } |
Что эквивалентно следующей конструкции:
|
StreamReader reader = File.OpenText («file.txt»); try { ... } finally { if (reader != null) ((IDisposable)reader).Dispose(); } |
Выбрасывание исключений
Исключение может быть выброшено автоматически во время выполнения программы либо явно в коде программы с помощью ключевого слова throw:
|
static void Display (string name) { if (name == null) throw new ArgumentNullException («name»); Console.WriteLine (name); } |
Также исключение может быть выброшено повторно внутри блока catch:
|
try { ... } catch (Exception ex) { // логирование ошибки ... throw; // повторное выбрасывание того же самого исключения } |
Такой подход позволяет заносить ошибки в лог без их дальнейшего поглощения. Также это позволяет уклониться от обработки неожиданных исключений.
Если throw заменить на throw ex, то пример по прежнему будет работать, но свойство исключения StackTrace не будет отражать исходную ошибку.
Другой распространенный сценарий использования повторного выбрасывания исключения — повторное выбрасывание более специфического и конкретного типа исключения, чем было перехвачено ранее:
|
try { ... // парсинг даты рождения из xml-данных } catch (FormatException ex) { throw new XmlException («Неправильная дата рождения», ex); } |
В таких случаях необходимо передать исходное исключение в качестве первого параметра конструктора нового исключения, ссылка на объект исходного исключения позже будет доступна через свойство InnerException внутреннего исключения.
Основные свойства System.Exception
К наиболее важным свойствам класса System.Exception можно отнести:
StackTrace— строка, представляющая все методы, которые были вызваны, начиная с того, в котором было выброшено исключение, и заканчивая тем, в котором содержится блокcatch, перехвативший исключение;Message— строка с описанием ошибки;InnerException— содержит ссылку на объектExeption, который вызвал текущее исключение (например, при повторном выбрасывании исключения).
Основные типы исключений
Следующие типы исключений являются наиболее распространенными в среде CLR и .NET Framework. Их можно выбрасывать непосредственно или использовать как базовые классы для пользовательских типов исключений.
System.ArgumentException— выбрасывается при вызове функции с неправильным аргументом.System.ArgumentNullException— производный отArgumentExceptionкласс, выбрасывается если один из аргументов функции неожиданно равенnull.System.ArgumentOutOfRangeException— производный отArgumentExceptionкласс, выбрасывается когда аргумент функции имеет слишком большое или слишком маленькое значение для данного типа (обычно касается числовых типов). Например, такое исключение будет выброшено если попытаться передать отрицательное число в функцию, которая ожидает только положительные числа.System.InvalidOperationException— выбрасывается когда состояние объекта является неподходящим для нормального выполнения метода, например, при попытке прочесть не открытый файл.System.NotSupportedException— выбрасывается, когда запрошенный функционал не поддерживается, например, если попытаться вызвать методAddдля коллекции доступной только для чтения (свойство коллекцииIsReadOnlyвозвращаетtrue).System.NotImplementedException— выбрасывается, когда запрошенный функционал еще не реализован.System.ObjectDisposedException— выбрасывается при попытке вызвать метод объекта, который уже был уничтожен (disposed).
Директивы препроцессора
Директивы препроцессора снабжают компилятор дополнительной информацией об областях кода. Самые распространенные директивы препроцессора — условные директивы, позволяющие включить или исключить области кода из компиляции.
|
#define DEBUG class MyClass { int x; void Foo() { # if DEBUG Console.WriteLine («Testing: x = {0}», x); # endif } } |
В этом классе инструкции в методе Foo скомпилируются если определен символ DEBUG, а если его удалить — инструкции не скомпилируются. Символы препроцессора могут быть определены в исходном коде (как в примере), а могут быть переданы компилятору в командной строке с помощью параметра /define:symbol.
С директивами #if и #elif можно использовать операторы ||, && и ! с несколькими символами:
Директивы #error и #warning предотвращают некорректное использование условных директив, заставляя компилятор генерировать предупреждение или ошибку при передаче неверного набора символов.
Директивы препроцессора схожи с условными конструкциями и статическими переменными, однако дают возможности, недоступные для последних:
- условное включение атрибута
- изменение типа, объявляемого для переменной
- переключение между разными пространствами имен или псевдонимами типа в директиве using:
using TestType =
#if V2
MyCompany.Widgets.GadgetV2;
#else
MyCompany.Widgets.Gadget;
#endif
- создавать новые версии кода и быстро переключаться между ними при компиляции
- создавать библиотеки, компилируемые для разных версий .NET Framework
Полный список директив препроцессора:
#define symbol— определяет символ#undef symbol— удаляет символ#if symbol [оператор symbol2]...— условная компиляция; допустимые операторы==,!=,&&и||#else— выполняет код после#endif#elif symbol [оператор symbol2]— объединяет#elseи#if#endif— конец условных директив#warning text— текст предупреждения, которое появится в выдаче компилятора#error text— текст ошибки, которая появится в выдаче компилятора#line [число["файл"] | hidden]— число указывает номер строки в исходном коде; файл — имя файла, которое появится в выдаче компилятора; hidden — дает указание дебагеру пропустить код от этой точки до следующей директивы#line#region name— отмечает начало области#endregion— отмечает конец области#pragma warning
Pragma Warning
Компилятор генерирует предупреждения, когда что-то в коде ему кажется неуместным (но корректным). В отличии от ошибок предупреждения не препятствуют компиляции программы. Предупреждения компилятора могут быть очень полезны при поиске багов в программе. Однако часто предупреждения оказываются ложными, поэтому целесообразно иметь возможность получать предупреждения только о действительных багах. С этой целью компилятор дает возможность выборочно подавить предупреждения с помощью директивы #pragma warning.
|
public class Foo { static void Main() { } #pragma warning disable 414 static string Message = «Hello»; #pragma warning restore 414 } |
В примере мы указываем компилятору не выдавать предупреждения о том, что поле Message не используется.
Если не указывать номер директива #pragma warning отменит или восстановит вывод всех предупреждений.
Если скомпилировать программу с параметром /warnaserror, то все не отмененные директивой #pragma warning предупреждения будут расцениваться компилятором как ошибки.
Атрибут Conditional
Атрибут Conditional указывает компилятору на необходимость игнорировать все обращения к определенному классу или методу, если заданный символ не был определен:
|
[Conditional («LOGGINGMODE»)] static void LogStatus (string msg) { ... } |
Это равносильно тому, что каждый вызов метода будет окружен условными директивами:
|
#if LOGGINGMODE LogStatus («Message Headers: « + GetMsgHeaders()); #endif |
Классы Debug и Trace
Статические классы Debug и Trace предлагают базовые возможности логирования. Оба класса схожи, отличие заключается в их назанчении. Класс Debug предназначен для отладочных сборок, класс Trace — для отладочных и финальных. В связи с этим все методы класса Debug определены с атрибутом [Conditional("DEBUG")], а методы класса Trace — с атрибутом [Conditional("TRACE")]. Это значит, что все обращения к Debug и Trace будут подавляться компилятором, пока не определен символ DEBUG или TRACE.
Класс Debug и Trace определяют методы Write, WriteLine и WriteIf. По умолчанию они отправляют сообщения в окно вывода отладчика:
|
Debug.Write («Data»); Debug.WriteLine (23 * 34); int x = 5, y = 3; Debug.WriteIf (x > y, «x is greater than y»); |
Класс Trace также содержит методы TraceInformation, TraceWarning и TraceError. Их действия зависят от зарегистрированных прослушивателей.
TraceListener
Классы Debug и Trace имеют свойство Listeners, которое представляет собой статическую коллекцию экземпляров TraceListener. Они отвечают за обработку данных, возвращаемых методами Write, Fail и Trace.
По умолчанию коллекция Listeners обоих классов включает единственный прослушиватель — DefaultTraceListener — стандартный прослушиватель, имеющий две ключевые возможности:
- при подключении к отладчику (например, Visual Studio) сообщения записываются в окно вывода отладчика, во всех остальных случаях сообщения игнорируются
- при вызове метода
Failотображается диалоговое окно, запрашивающее у пользователя дальнейшие действия: продолжить, прервать или повторить отладку (независимо от того, подключен ли отладчик)
Это поведение можно изменить или дополнить, удалив (на обязательно) стандартный прослушиватель и/или добавив один или более собственных прослушивателей.
Прослушиваетли трассировки можно написать с нуля (создав производный класс от TraceListener) или воспользоваться готовыми классами:
TextWriterTraceListenerзаписывает вStreamилиTextWriterили добавляет в файл; имеет четыре подкласса:ConsoleTraceListener,DelimitedListTraceListener,XmlWriterTraceListenerиEventSchemaTraceListenerEventLogTraceListenerзаписывает в журнал событий WindowsEventProviderTraceListenerзаписывает в систему трассировки событий Windows (Event Tracing for Windows — ETW)WebPageTraceListenerвыводит на веб-страницу ASP.NET
Ни один из этих прослушивателе не отображает диалоговое окно при вызове Fail, это делает только DefaultTraceListener.
|
// Удалить стандартный прослушиватель, очистив коллекцию прослушивателей: Trace.Listeners.Clear(); // Добавить средство записи в файл trace.txt: Trace.Listeners.Add (new TextWriterTraceListener («trace.txt»)); // Добавит средство записи в консоль: System.IO.TextWriter tw = Console.Out; Trace.Listeners.Add (new TextWriterTraceListener (tw)); // Добавить средство записи в журнал событий Windows: if (!EventLog.SourceExists («DemoApp»)) EventLog.CreateEventSource («DemoApp», «Application»); Trace.Listeners.Add (new EventLogTraceListener («DemoApp»)); |
В случае журнала событий Windows сообщения, отправляемые с помощью Write, Fail или Assert, записываются как сведения, а сообщения методов TraceWarning и TraceError записываются как предупреждения или ошибки.
Каждый экземпляр TraceListener имеет свойство Filter и TraceFilter, с помощью которых можно управлять, будет ли сообщение записано в этот прослушиватель. Для этого необходимо создать экземпляр классов EventTypeFilter или SourceFilter (производных от TraceFilter) или создать свой класс, наследующий от TraceFilter и переопределить в нем метод ShouldTrace.
В TraceListener также определены свойства IndentLevel и IndentSize для управления отступами и свойство TraceOutputOptions для записи дополнительных данных:
|
TextWriterTraceListener tl = new TextWriterTraceListener (Console.Out); tl.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.Callstack; // Это применяется при использовании метода Trace: Trace.TraceWarning («Orange alert»); DiagTest.vshost.exe Warning: 0 : Orange alert DateTime=2007—03—08T05:57:13.6250000Z Callstack= at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo) at System.Environment.get_StackTrace() at ... |
Прослушиватели, которые записывают данные в поток, кэшируются. По этой причине данные не появляются в потоке немедленно, а также поток перед завершением приложения должен быть закрыт, или хотя бы сброшен, чтоб не потерять данные в кэше. Для этой цели классы Trace и Debug содержат статические методы Close и Flush, которые вызывают Close и Flush во всех прослушивателях (а они в свою очередь закрывают или сбрасывают все потоки). Метод Close вызывает метод Flush, закрывает файловые дескрипторы и предотвращает дальнейшую запись.
Классы Trace и Debug также определяют свойство AutoFlush, которое если равно true вызывает Flush после каждого сообщения.
Fail и Assert
Классы Debug и Trace содержат методы Fail и Assert.
Метод Fail отправляет сообщения каждому TraceListener:
|
Debug.Fail («File data.txt does not exist!»); |
Метод Assert вызывает Fail если аргумент типа bool равен false. Это называется созданием утверждения и указывает на ошибку, если оно нарушено. Можно также создать необязательное сообщение об ошибке:
|
Debug.Assert (File.Exists («data.txt»), «File data.txt does not exist!»); var result = ... Debug.Assert (result != null); |
Методы Write, Fail и Assert также могут принимать категорию в виде строки ,которая может быть использована при обработке вывода.







Сообщение было отмечено elsum как решение