Как правильно обращаться с блоками Try/Catch и ошибками в целом при использовании нескольких классов?
Я пытаюсь понять правильные структуры программы здесь, чтобы облегчить все. В основном, куда" класть " вещи.
Например:
У вас есть 2 класса.
Класс 1-Ваш основной.
Оба класса имеют много методов.
Класс 1 вызывает экземпляр класса 2 и запускает метод. Предполагается, что этот метод возвращает значение.
Вопрос 1:
Должен ли я иметь блок try / catch внутри этого метода (в классе 2)?
Вопрос 2:
Должен блок try / catch находится там, где я вызываю метод (в классе 1)?
try
method();
catch
...
Вопрос 3:
При выполнении метода, который находится в классе 2, когда речь заходит о возврате значения, должен ли я когда-либо возвращать "код ошибки", а затем иметь дело с этим кодом в вызывающем классе?
Вопрос 4:
Когда происходит ошибка и мне нужно "остановить" программу, должен ли я использовать операторы if / else, чтобы код двигался вперед только при соблюдении правильных условий, или я должен использовать ключевое слово "break" больше часто?
Вопрос 5:
Возможности для ошибок могут быть бесконечны, особенно если у вас есть средние и большие программы. Как вы, ребята, справляетесь с неизвестными ошибками, с которыми вы можете столкнуться, когда пользователь запускает вашу программу?
5 ответов:
Исключениями являются исключительными. Вы не должны использовать исключения для обычного потока программ. (Если вы скажете:" О да, я ожидал этого", это, вероятно, не должно быть исключением.)
Обработайте исключение там, где оно нуждается в обработке. Если вы можете пережить функцию без этого блока
try-catch, то вы должны справиться с ней там. Аналогично, если вам нужно обернуть некоторые вещи, вы также можете добавить блокfinally(usingпохож наfinallyв C# - он компилируется доtry-finally, но не так так же крепко, как написать его самому. Он просто вызывает.Dispose()на указанный вами одноразовый объект).Но если вам нужно выйти из этой функции, или вы запускаете строку функций, которые должны все преуспеть в вашем основном классе, может быть, лучше сделать обработку в вашем классе 1.
Предостережение: есть исключения (ха!) ко всем правилам. По мере того, как вы программируете больше, вы можете получить интуитивное представление о том, где должна выполняться обработка ошибок, но часто их будет больше одного вариант и он может быть не совсем ясным.
В общем, ответ на все эти вопросы - "это зависит". Ясно, что вам нужно сделать, зависит от конкретных обстоятельств ситуации и приложения, которое она содержит.
С практической точки зрения я обычно следую нескольким правилам:
1. Используйте обработку исключений вместо кодов ошибок
2. Используйте try/catch только тогда, когда я знаю, как обрабатывать исключениеЯсно, что никто не может сказать вам, нужно ли вам попробовать / поймать в рамках метода, не зная, что это метод делает и можно ли обрабатывать какие-либо исключения.
Действительно ли код ошибки применим, зависит от вас. Я вообще считаю, что это неприменимо; но иногда это может быть так. В этих случаях я рассматриваю его только как применимое, если вызывающий будет всегда использовать код и не передавать его дальше. "GetErrorCode" может быть хорошим примером случая, когда код ошибки может быть применим.
Вы не можете " обрабатывать "(то есть компенсировать)" неизвестные " ошибки. То рекомендуемая практика-не обрабатывать исключение и позволить дескриптору завершиться изящно, потому что он находится в неизвестном состоянии.
Перехват исключений и возврат кодов ошибок / bools приводит к" стрелочному " коду, например:
К сожалению, я поддерживаю сложный проект, в котором исключения рассматриваются как Эбола и сдерживаются, как только они появляются. На самом деле это только усложняет понимание и поддержку кода.if(Func1()) { if (Func2()) { if (Func3()) { } } }
Это зависит от того, как вы визуализируете и структурируете свое приложение. Являются ли классы 1 и 2 частью одного и того же модуля или они находятся в разных модулях? В общем случае модуль предоставляет "API", и вызывающий" API " должен перехватывать ошибки и исключения. Взгляните назащитное Программирование .
Вопрос 1: Должен ли я иметь блок try/catch внутри этого метода (в классе 2)?
Если класс 2 является отдельным модулем и вы не хотите распространять исключения на модуль вызывающего абонента, тогда да. Если хочешь, то нет. Исключения, вызванные из этого класса / модуля, затем должны быть задокументированы.
Если классы 1 и 2 находятся в одном модуле, то опять же это зависит от того, хотите ли вы обрабатывать исключения внутри внутренних классов или нет.
Вопрос 2: должен ли блок try / catch находиться там, где я вызываю метод (в классе 1)?
Если вы хотите гарантировать, что класс 1 не создает дополнительных исключений, то да.
Вопрос 3: При выполнении метода, который находится в классе 2, когда речь заходит о возврате значения, должен ли я когда-либо возвращать "код ошибки", а затем иметь дело с этим кодом в вызывающем классе?
Если вы хотите бросить исключение возврата кода ошибки, это снова решение проектирования / реализации.
Вопрос 4: Когда происходит ошибка и мне нужно "остановить" программу, должен ли я использовать операторы if/else, чтобы код двигался вперед только при соблюдении правильных условий, или я должен использовать ключевое слово "ломать" чаще?
Для использования break вам понадобится цикл в вызывающем объекте.
Вопрос 5: возможности для ошибок могут быть бесконечны, особенно если у вас есть средние и большие программы. Как вы, ребята, справляетесь с неизвестными ошибками, с которыми вы можете столкнуться, когда пользователь запускает вашу программу?Большие программы делятся на модули и могут быть закодированы разными разработчиками. Таким образом, контракт на проектирование и интерфейс становится важным здесь.
Я в общем согласен с Давидом и Петром... Единственное, что я хотел бы добавить, это быть осторожным с исключениями, которые вы ловите, когда вы их ловите... у Рихтера есть очень интересная глава, посвященная обработке исключений и тому, как исключения должны были наследоваться в сравнении с тем, как они были фактически реализованы... Но даже несмотря на это, это (IMO) лениво или, по крайней мере, плохо продумано, если вы постоянно ловите общий класс исключений...
Если вы занимаетесь чтением/записью файлов, вы может очень хорошо хотеть поймать соответствующие исключения IO, но последовательно поймать самый общий класс исключений может привести вас к проблемам, если, скажем, NullReferenceException будет брошено, и ваш try/catch только защищал от исключений IO... Ваш блок catch будет пытаться исправить (то, что он предполагал) исключение ввода-вывода, и это может привести ваш код в ужасно нестабильное состояние.
Кроме того, будьте очень осторожны, продолжая повторять исходную ошибку, если вы не уверены, что вы По-настоящему справился с этим должным образом... Если бы вы написали библиотеку, опубликовали ее и проглотили все ошибки, потому что думали, что делаете лучшее, то у того, кто потребляет вашу библиотеку, не было бы никакого способа отладить то, что происходит... Исключения также попадают в журналы серверов, так что проглоченная ошибка никогда не попадет туда.
Единственное место, где я бы рекомендовал ловить общую ошибку, находится прямо на уровне пользовательского интерфейса, где вы, очевидно, не хотите показывать пользователю YSOD, но даже в этом случае ваш catch, вероятно, должен сделать некоторые записи или что-то, чтобы помочь вам отладить позже.
Comments