В настоящее время я пишу свое первое приложение Windows Forms. Я прочитал несколько книг по C #, поэтому у меня есть относительно хорошее представление о том, какие языковые функции C # имеют дело с исключениями. Однако все они носят теоретический характер, поэтому у меня еще нет ощущения, как перевести базовые концепции в хорошую модель обработки исключений в моем приложении.
Кто-нибудь хотел бы поделиться какой-нибудь мудростью по этому поводу? Публикуйте любые распространенные ошибки, которые вы видели у новичков, таких как я, и любые общие советы по обработке исключений таким образом, чтобы мое приложение было более стабильным и надежным.
Основные вещи, над которыми я сейчас пытаюсь работать, это:
- Когда мне следует повторно генерировать исключение?
- Стоит ли мне попытаться создать какой-то центральный механизм обработки ошибок?
- Ухудшает ли обработка исключений, которые могут возникнуть, по сравнению с упреждающим тестированием таких вещей, как наличие файла на диске?
- Следует ли весь исполняемый код заключать в блоки try-catch-finally?
- Могут ли быть допустимы пустые блоки catch?
Все советы получены с благодарностью!
источник
ApplicationException
для тех случаев отказа, которые приложение должно разумно различать и обрабатывать.Есть отличный код статья CodeProject . Вот пара основных моментов:
источник
Обратите внимание, что в Windows Forms есть собственный механизм обработки исключений. Если кнопка в форме нажата и ее обработчик генерирует исключение, которое не было перехвачено обработчиком, Windows Forms отобразит свой собственный диалог необработанного исключения.
Чтобы предотвратить отображение диалогового окна необработанных исключений и перехватить такие исключения для ведения журнала и / или для предоставления собственного диалогового окна ошибок, вы можете присоединиться к событию Application.ThreadException перед вызовом Application.Run () в вашем методе Main ().
источник
Все советы, опубликованные здесь, хороши и заслуживают внимания.
Одна вещь, которую я хотел бы расширить, - это ваш вопрос: «Ухудшает ли обработка исключений, которые могут возникнуть, по сравнению с упреждающим тестированием таких вещей, как наличие файла на диске?»
Наивное эмпирическое правило гласит: «Блоки попыток / уловок стоят дорого». На самом деле это не так. Пробовать не дорого. Это ловушка, когда система должна создать объект Exception и загрузить его трассировкой стека, что дорого. Есть много случаев, когда исключение является достаточно исключительным, чтобы обернуть код в блок try / catch.
Например, если вы заполняете Словарь, это:
часто быстрее, чем это делать:
для каждого отдельного элемента, который вы добавляете, потому что исключение возникает только тогда, когда вы добавляете повторяющийся ключ. (Это делают агрегированные запросы LINQ.)
В приведенном вами примере я бы использовал try / catch почти не задумываясь. Во-первых, тот факт, что файл существует, когда вы его проверяете, не означает, что он будет существовать, когда вы его откроете, поэтому вам действительно следует обрабатывать исключение в любом случае.
Во-вторых, и я думаю, что это более важно, если только вы: а) ваш процесс не открывает тысячи файлов и б) вероятность того, что файл, который он пытается открыть, не существует, нетривиально низка, снижение производительности при создании исключения - это не то, что вы ' когда-нибудь заметит. Вообще говоря, когда ваша программа пытается открыть файл, она пытается открыть только один файл. Это тот случай, когда написание более безопасного кода почти наверняка будет лучше, чем написание максимально быстрого кода.
источник
dict[key] = value
что должно быть так же быстро, если не быстрее ..Вот несколько рекомендаций, которым я следую
Fail-Fast: это больше похоже на руководство по созданию исключений. Для каждого сделанного вами предположения и каждого параметра, который вы вводите в функцию, выполните проверку, чтобы убедиться, что вы начинаете с правильных данных и что ваши предположения Делаем верны. Типичные проверки включают: аргумент не равен нулю, аргумент находится в ожидаемом диапазоне и т. Д.
При повторном выбросе сохранить трассировку стека - это просто переводится на использование throw при повторном выбросе вместо throw new Exception (). В качестве альтернативы, если вы чувствуете, что можете добавить дополнительную информацию, оберните исходное исключение как внутреннее исключение. Но если вы поймаете исключение только для того, чтобы зарегистрировать его, обязательно используйте throw;
Не перехватывайте исключения, с которыми вы не можете справиться, поэтому не беспокойтесь о таких вещах, как OutOfMemoryException, потому что, если они возникнут, вы все равно не сможете многое сделать.
Перехватите глобальные обработчики исключений и убедитесь, что в журнал занесено как можно больше информации. Для winforms перехватывают события необработанного исключения домена приложения и потока.
Производительность следует принимать во внимание только тогда, когда вы проанализировали код и увидели, что он вызывает узкое место в производительности, по умолчанию оптимизируйте его для удобочитаемости и дизайна. Итак, что касается вашего первоначального вопроса о проверке существования файла, я бы сказал, что это зависит от того, если вы можете что-то сделать с файлом, который не существует, тогда да, сделайте эту проверку, иначе, если все, что вы собираетесь сделать, это выбросить исключение, если файл не там тогда я не вижу в этом смысла.
Определенно бывают случаи, когда требуются пустые блоки catch, я думаю, что люди, которые говорят иначе, не работали над кодовыми базами, которые развивались в течение нескольких выпусков. Но их следует прокомментировать и просмотреть, чтобы убедиться, что они действительно нужны. Наиболее типичный пример - разработчики используют try / catch для преобразования строки в целое число вместо использования ParseInt ().
Если вы ожидаете, что вызывающий ваш код сможет обрабатывать условия ошибки, создайте пользовательские исключения, которые подробно описывают непредвиденную ситуацию и предоставляют соответствующую информацию. В противном случае просто придерживайтесь встроенных типов исключений, насколько это возможно.
источник
Application.ThreadException
событие, когда ссылались на событие «необработанное исключение потока»?Мне нравится философия не ловить то, что я не собираюсь обрабатывать, что бы это ни значило в моем конкретном контексте.
Я ненавижу, когда вижу такой код, как:
Я наблюдал это время от времени, и довольно сложно найти проблемы, когда кто-то «ест» исключения. Мой коллега делает это, и это, как правило, вносит свой вклад в постоянный поток проблем.
Я повторно выбрасываю, если есть что-то, что мой конкретный класс должен сделать в ответ на исключение, но проблема должна быть устранена до того, как вызывается метод, в котором это произошло.
Я считаю, что код следует писать проактивно и что исключения должны быть для исключительных ситуаций, а не для избежания тестирования условий.
источник
Я сейчас ухожу, но расскажу вам, где использовать обработку исключений. Я постараюсь ответить на другие ваши вопросы, когда вернусь :)
*В пределах разумного. Нет необходимости проверять, попал ли, скажем, космический луч в ваши данные, заставив пару битов перевернуться. Понимание того, что «разумно» - это приобретенный навык для инженера. Трудно дать количественную оценку, но легко интуитивно. То есть я могу легко объяснить, почему я использую try / catch в каком-то конкретном случае, но мне трудно наделить других такими же знаниями.
Я, например, стараюсь избегать архитектур, в значительной степени основанных на исключениях. Команда try / catch не влияет на производительность как таковая, она возникает, когда генерируется исключение, и код может пройти несколько уровней стека вызовов, прежде чем что-либо обработает его.
источник
Золотое правило, которого пытались придерживаться, - обрабатывать исключение как можно ближе к источнику.
Если вы должны повторно вызвать исключение, попробуйте добавить к нему, повторное создание исключения FileNotFoundException не очень помогает, но выброс исключения ConfigurationFileNotFoundException позволит захватить его и обработать где-нибудь в цепочке.
Еще одно правило, которому я стараюсь следовать, - не использовать try / catch как форму потока программы, поэтому я проверяю файлы / соединения, проверяю, были ли инициированы объекты и т. Д., Перед их использованием. Try / catch должен быть для исключений, вещей, которые вы не можете контролировать.
Что касается пустого блока catch, если вы делаете что-либо важное в коде, который сгенерировал исключение, вы должны как минимум повторно выбросить исключение. Если код, который вызвал исключение, не имеет последствий, то почему вы его вообще написали.
источник
вы можете перехватить событие ThreadException.
Выберите проект приложения Windows в обозревателе решений.
Откройте созданный файл Program.cs, дважды щелкнув по нему.
Добавьте следующую строку кода в начало файла кода:
В методе Main () добавьте следующую строку в качестве первой строки метода:
Добавьте следующее под методом Main ():
Добавьте код для обработки необработанного исключения в обработчике событий. Любое исключение, которое не обрабатывается где-либо еще в приложении, обрабатывается приведенным выше кодом. Чаще всего этот код должен регистрировать ошибку и отображать сообщение для пользователя.
ссылка: https://blogs.msmvps.com/deborahk/global-exception-handler-winforms/
источник
Исключения дороги, но необходимы. Вам не нужно заключать все в try catch, но вам нужно убедиться, что исключения всегда в конечном итоге перехватываются. Во многом это будет зависеть от вашего дизайна.
Не выполняйте повторный вызов, если можно позволить возникновению исключения. Никогда не позволяйте ошибкам оставаться незамеченными.
пример:
Если DoStuff пойдет не так, вы все равно захотите выручить его. Исключение будет передано в main, и вы увидите последовательность событий в трассировке стека ex.
источник
Везде, но методы конечного пользователя ... например, обработчики нажатия кнопки
Я пишу файл журнала ... довольно просто для приложения WinForm
Я не уверен в этом, но я считаю, что это хорошая практика для показа исключений ... Я имею в виду, что вы можете спросить, существует ли файл и не вызывает ли он исключение FileNotFoundException
Yeap
Да, допустим, вы хотите показать дату, но не знаете, как эта дата была сохранена (дд / мм / гггг, мм / дд / гггг и т. Д.), Вы пытаетесь разобрать ее, но если это не удается, просто продолжайте .. . если это не имеет отношения к вам ... я бы сказал да, есть
источник
Одна вещь, которую я очень быстро усвоил, - это заключать абсолютно каждый фрагмент кода, который взаимодействует с чем-либо вне потока моей программы (например, файловая система, вызовы базы данных, пользовательский ввод), с блоками try-catch. Try-catch может снизить производительность, но обычно в этих местах кода это не заметно и окупается безопасностью.
Я использовал пустые блоки-уловки в местах, где пользователь мог бы сделать что-то, что на самом деле не "неправильно", но может вызвать исключение ... на ум приходит пример в GridView, если пользователь DoubleCLicks серый заполнитель ячейка в верхнем левом углу, она вызовет событие CellDoubleClick, но ячейка не принадлежит строке. В этом случае вы не действительно необходимо отправить сообщение, но если вы его не поймаете, пользователю будет выдана ошибка необработанного исключения.
источник
При повторной генерации исключения ключевое слово выбрасывается самим собой. Это вызовет перехваченное исключение и по-прежнему сможет использовать трассировку стека, чтобы узнать, откуда оно взялось.
это приведет к тому, что трассировка стека завершится оператором catch. (избегайте этого)
источник
По моему опыту, я счел нужным отлавливать исключения, когда знаю, что собираюсь их создавать. В случаях, когда я использую веб-приложение и выполняю Response.Redirect, я знаю, что получу исключение System.ThreadAbortException. Так как это сделано намеренно, у меня есть ловушка для определенного типа и я просто проглатываю ее.
источник
Я полностью согласен с правилом:
Причина в том, что:
ForceAssert.AlwaysAssert - это мой личный способ Trace.Assert, независимо от того, определен ли макрос DEBUG / TRACE.
Может быть, цикл разработки: я заметил уродливое диалоговое окно Assert или кто-то мне пожаловался на это, затем я возвращаюсь к коду и выясняю причину возникновения исключения и решаю, как его обработать.
Таким образом, я могу записать МОЙ код за короткое время и защитить меня от неизвестного домена, но всегда быть замеченным, если происходят ненормальные вещи, таким образом, система становится безопасной и более безопасной.
Я знаю, что многие из вас не согласятся со мной, потому что разработчик должен знать каждую деталь своего кода, честно говоря, я тоже был пуристом в старые времена. Но теперь я узнал, что эта политика более прагматична.
Для кода WinForms я всегда соблюдаю золотое правило:
это защитит ваш пользовательский интерфейс, и вы всегда сможете его использовать.
Для снижения производительности снижение производительности происходит только тогда, когда код достигает catch, выполнение кода попытки без фактического возникшего исключения не имеет значительного эффекта.
Исключение должно быть маловероятным, иначе это не исключение.
источник
Вы должны думать о пользователе. Сбой приложения - это последнийвещь, которую хочет пользователь. Следовательно, любая операция, которая может завершиться ошибкой, должна иметь блок try catch на уровне пользовательского интерфейса. Необязательно использовать try catch в каждом методе, но каждый раз, когда пользователь что-то делает, он должен уметь обрабатывать общие исключения. Это никоим образом не освобождает вас от проверки всего, чтобы предотвратить исключения в первом случае, но нет сложного приложения без ошибок, и ОС может легко добавить неожиданные проблемы, поэтому вы должны предвидеть непредвиденное и убедиться, что пользователь хочет использовать его. операции не будет потери данных из-за сбоя приложения. Нет необходимости когда-либо допускать сбой вашего приложения, если вы перехватите исключения, оно никогда не будет в неопределенном состоянии, и пользователь ВСЕГДА испытывает неудобства из-за сбоя. Даже если исключение находится на самом верхнем уровне, Отсутствие сбоев означает, что пользователь может быстро воспроизвести исключение или, по крайней мере, записать сообщение об ошибке, что значительно поможет вам решить проблему. Конечно, это намного больше, чем просто получить сообщение об ошибке, а затем увидеть только диалоговое окно с ошибкой Windows или что-то в этом роде.
Вот почему вы НИКОГДА не должны зазнаваться и думать, что в вашем приложении нет ошибок, это не гарантируется. И это очень небольшое усилие, чтобы обернуть некоторые блоки try catch вокруг соответствующего кода и показать сообщение об ошибке / зарегистрировать ошибку.
Как пользователь, я, конечно, серьезно злюсь, когда броски, офисное приложение или что-то еще дает сбой. Если исключение настолько велико, что приложение не может продолжить работу, лучше отобразить это сообщение и сообщить пользователю, что делать (перезапустить, исправить некоторые настройки ОС, сообщить об ошибке и т. Д.), Чем просто аварийно завершить работу и все.
источник