20

Есть ли случаи, когда это хорошая идея, чтобы throw ошибок, которых можно избежать?Есть ли причина бросать исключение DivideByZeroException?

Я имею в виду конкретно о DivideByZeroException и ArgumentNullException

Например:

double numerator = 10; 
double denominator = getDenominator(); 

if(denominator == 0){ 
    throw new DivideByZeroException("You can't divide by Zero!"); 
} 

Есть ли какие-либо причины для метания ошибку, как это?

Примечание: Я не говорю о ловли эти ошибки, но конкретно знать, если когда-либо веские причины бросать их.

Только чтобы напомнить:

Я знаю, что в примере, который я дал вам, вероятно, будет лучше обработки ошибки. Возможно, этот вопрос нужно перефразировать. Есть ли какие-либо причины для throw одной из этих ошибок вместо обращения к ней это.

+0

Кодовые контракты могут облегчить эту проблему. –

+0

Примечание: ответы Juhar и nobugz оба очень хороши. – Armstrongest

ответ

19

Предположим, вы пишете библиотеку для работы с действительно большими целыми числами, которые не вписываются в Int64, тогда вам может понадобиться бросить исключение DivideByZeroException для алгоритма деления, который вы пишете.

+0

Хороший ответ, и вы поднимаете хороший краевой пункт. – Beska

+0

Не могли бы вы рассказать об этом. Это звучит как интересный краевой случай. – Armstrongest

+6

@Atomiton - Я уже делал это раньше. Если вы написали математическую библиотеку, а код вызова подает вам нулевой знаменатель, что еще вы могли бы сделать, кроме как выбросить исключение? Математическая библиотека не знает, что вы пытаетесь сделать. Не всегда-правильный способ справиться с ситуацией в этом месте. Только код вызова имеет достаточно большого изображения, чтобы знать, что с ним делать.Поэтому бросьте исключение. –

0

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

По крайней мере, это то, что сказал мне мой старший разработчик, когда я попытался поймать DivideByZeroException много лун назад.

+2

Вы должны защищаться против него, но это не значит, что вы обязательно должны предполагать, что этого никогда не произойдет, а не поймать. Вы можете быть потрясающими и обрабатывать каждый случай с пользовательским интерфейсом ... но потом, позже, кто-то добавляет некоторые новые функции в интерфейс, и они не такие умные ... бум. Если вы можете изящно поймать исключение, сделать все необходимые уведомления и вести журнал, а затем продолжить, это может быть хорошей идеей. – Beska

+0

хорошо пункт. но если вы всегда это делаете: if (знаменатель == 0) {}, тогда у вас не будет проблемы. Но я вижу вашу точку зрения. –

+0

@Beska - Нет, вы никогда не должны продолжать программу в недопустимом или неизвестном состоянии. При возникновении непредвиденных ошибок необходимо выпустить и зарегистрировать надлежащее уведомление, а затем программа должна внезапно погибнуть. Обработка ошибок «изящно» - это короткий путь к кодовому коду и черту обслуживания. –

-1

Бросать исключение - это дорогостоящая вещь с точки зрения ресурса. Вы уже предотвратили появление исключения, поэтому зачем бросать его? Если вам нужно сообщить пользователю, используйте механизм обмена сообщениями. Если вам нужно знать об этом самостоятельно, запишите его.

+0

Точно. Я с тобой согласен. Итак, есть ли ЛЮБОЕ случаи, когда кто-то «бросает» «DivideByZeroException», я не могу думать ни о каком. Вот почему я задал вопрос о SO. – Armstrongest

+2

Если вы не собираетесь генерировать исключение, какое значение будет использовать ваш метод деления в этом сценарии? – cdkMoose

+0

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

4

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

В этом случае, похоже, что ноль будет недопустимым пользователем. Вы должны проверить недействительный ввод пользователя и обрабатывать его соответственно. ПЕРЕД НАЧАЛОМ вы догадались, что исключение будет использовано.

До тех пор, пока вы должным образом обрабатываете ввод, не должно быть причин для возникновения DivideByZeroException. Если вы получили DivideByZeroException даже после проверки ввода ... тогда вы знаете, что у вас есть реальная проблема (в этом случае исключение является подходящим).

+2

Я согласен с вашим общим моментом, хотя я думаю, что старая поговорка об исключениях только для «исключительных случаев» выше. Кшиштоф Квалина, безусловно, так думает - http://blogs.msdn.com/kcwalina/archive/2008/07/17/ExceptionalError.aspx –

+0

@Dan На мой взгляд, Кшиштоф просто пересчитывает определение того, что я считаю исключением case (случай, в котором возникает реальная ошибка, а не то, что можно легко поймать с помощью проверки ввода и т. д.). –

+0

Но если вы пишете библиотеку, потребляемую другими ...? Я думаю, что в этом суть. Писатель библиотеки не может заранее определить, что будет исключительным, и что будет распространено, когда дело доходит до того, как кто-то использует свой API. –

0

Хорошая практика для выполнения этих проверок в верхней части функции перед началом обработки данных. Вместо этого бросание их (или любой другой метод выбрасывает эти исключения) в середине метода.

+1

Согласен. Однако это не то, о чем я просил. :-) – Armstrongest

3

Если вы говорите о коде, который непосредственно взаимодействует с пользовательским интерфейсом, то нет. Я не могу придумать ни одной причины, по которой тебе бы хотелось.

Однако, если вы строите класс/объект, используемый другими разработчиками, и они прошли в данных, которые явно глупы, а затем выведите соответствующую ошибку во время вашей проверки.

11

.NET runtime уже очень хорошо бросает эти исключения. Они также очень хорошо описывают, что не так, вы не можете добавить хороший комментарий к сообщению об исключении. «Вы не можете делить на ноль» не добавляет значения.

Однако вы можете избежать многих из этих исключений, просмотрев значения, переданные кодом клиента. Вы должны будете иметь аргумент ArgumentNullException с именем аргумента, если код клиента передал null, исключение ArgumentException, когда оно передало что-то, что может вызвать DivideByZero.

+0

Удалил мой ответ и проголосовал за вас ... вы сказали это более ясно, чем я. Престижность. – Beska

+0

Определенно это. Даже если вы пишете математическую библиотеку, вы не должны бросать DivideByZeroExceptions. По той же причине вы никогда не должны бросать исключение NullReferenceException, в основном: эти исключения говорят, что «библиотека багги». То, что вы хотите, чтобы сказать: «Вы неправильно используете библиотеку». Аргументы Исключения идеальны. – Joren

+1

Если вы хотите вывести «Исключения» с пользователя и использовать сообщение «Исключение», чтобы показать пользователю, где он поступил не так, может быть хорошей идеей предоставить настраиваемое сообщение. например, 'LiteralErrorMsg1.Text = ex.Message. Другим сценарием будет Локализация. Вы также можете показать сообщение об ошибке на языке пользователя. – Armstrongest

0

В теории (и практике тоже) определение и устранение/устранение ошибочных случаев лучше, чем рассмотрение их как исключений. Однако не всегда можно проверить каждый случай или путь через ваш код - также невозможно в каждом случае контролировать ваши входы.

Принцип хорошего дизайна заключается в том, чтобы ваша программа распознавала и изящно обрабатывала исключительные ситуации. Кроме того, рекомендуется предоставлять пользователям (и, в конечном итоге, самому) достаточно информации для диагностики ошибок, особенно тех, которые могут возникнуть после развертывания вашего кода. Таким образом, это делает иногда имеет смысл бросать исключения, такие как вид, иллюстрирующий, если он сделает ваш код приложения более надежным и легче диагностировать.

+0

Можете ли вы немного разработать или привести пример? Меня особенно интересует ваш второй момент ... что иногда это хорошая идея, чтобы выбросить ожидаемые ошибки, подобные этому (что в противном случае можно было бы обрабатывать) – Armstrongest

+0

@Atomiton - я рассматриваю его как защитную практику кодирования. Вы никогда не сможете быть на 100% уверены, что действительно охватили все пути и не позволили передать все ошибочные данные определенному телу кода. Таким образом, стоит иметь логику, которая обнаруживает такие ситуации (когда вы можете), чтобы в процессе производства вы могли предоставить достаточно деталей, чтобы помочь быстро диагностировать такие проблемы, если они действительно происходят. Основная предпосылка заключается в следующем: доказать, что конкретный вход никогда не будет передан методу * hard * - проверка ввода для достоверности в методе намного проще. http://en.wikipedia.org/wiki/Defensive_programming – LBushkin

5

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

Если вы пишете библиотеку maths и имеете функцию, называемую Divide(int a, int b), которая делит их, если кто-то хочет использовать ваш метод и проходит в ноль, вы захотите выбросить исключение, чтобы они, как разработчик, знали они прищурились.

Если вы не выбрали исключение, вы вводите ошибки в свой код. Если я использовал ваш метод разделения и поместил значения 10 и 0 в, что дает 10/0 и, следовательно, исключение, единственным правильным ответом будет ошибка. Если вы решите изменить значения, чтобы не возникала ошибка или возвращалось 0, это не то, что я ожидаю - я полагаю, что мое подразделение отлично работало и никогда не замечало проблемы. Я мог бы взять это 0 и уйти и использовать его в других вычислениях, не подозревая, что это неправильный ответ, потому что 10/0 не 0.

+0

10D/0D = double.Infinity, а не ошибка. В зависимости от характера приложения это может отображаться как символ бесконечности (∞) или отображаться как ошибка. –

+0

Ах! Отличный ответ! Итак ... вы выбросите ошибку в случаях, когда вы захотите выпустить Exception на более высокий уровень, а не обрабатывать его! – Armstrongest

+0

Но какова точка проверки и вручную выбрасывания исключения, когда вы могли бы просто запустить деление, и он будет генерировать исключение для вас? –

1

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

«В рамках исключения используются как для жестких ошибок и логических ошибок. Во-первых, это может быть трудно принять обработку исключений в качестве средства отчетности всех функциональных неудач. Однако, это важно, чтобы проектировал все общедоступные методы структуры , чтобы сообщать об ошибках метода , бросая исключение. "

Krzysztof Cwalina, Designing Reusable Frameworks

2

Если вы пишете библиотеку BigInteger, то вам совершенно необходимо бросить соответствующий DivideByZero исключение. Если вы пишете библиотеку корзины покупок, тогда ... ну, возможно, нет.

В настоящий момент я не могу придумать вескую причину, чтобы бросить NullReferenceException. Если вы создаете API с документацией, в которой говорится: «Первый параметр для HummingBirdFeeder.OpenSugarWaterDispenser(Dispenser dispenser, int flowRate) - это раздатчик сахарной воды, который вы хотите открыть». И если кто-то тогда приходит и передает нулевое значение этому методу, тогда вы должны обязательно бросить ArgumentNullException.

Сдача NullReferenceException из вашего API будет просто ленивой, хотя, потому что это неправильно, и это утечки некоторых ваших внутренних компонентов.

отредактирован ADD:

Теперь, когда вы изменили вопрос сослаться на ArgumentNullException, то ответ прост: да, вы определенно должны бросить такого рода исключения при таких обстоятельствах:

  • You пишут общедоступный метод.
  • Получение нулевого значения для аргумента является некорректным (т. Е. Метод не имеет смысла без этого конкретного аргумента).
  • Документация для метода указывает, что пустые значения не допускаются.

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

Если вы пишете частный или внутренний метод, то в большинстве случаев вам не нужно будет проверять параметры во время выполнения в сборке выпуска. Вы можете убедиться, что ваш собственный код правильно называет ваш собственный код. Одна вещь, которая помогает создать такую ​​уверенность, чтобы проверить параметры в отладочных путем добавления assersions:

Debug.Assert(dispenser != null); 

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

+0

Спасибо! На самом деле, я набрал NullReferenceException ... но думал ArgumentNullException. Благодаря! Я собираюсь исправить вопрос! – Armstrongest

1

слегка вводят в заблуждении названия здесь речь идет не о метании (специальный) DivideByZeroException, а скорее вопрос:

Должен ли я использовать исключение во время проверки пользовательского ввода?

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

Однако при проверке «данных» в более глубоких слоях приложения обычно выбрасывается исключение.

+0

Спасибо за комментарий. Но, я хотел знать, были ли случаи для того, чтобы бросить ошибку, которую так легко проверить, поэтому я специально упомянул об этом. Концепция более глубоких слоев (уже несколько человек) - это то, что я искал. – Armstrongest

0

Учтите, что для удвоений деление на ноль фактически приведет к значению: double.Infinity, double.NegativeInfinity или double.NaN, в зависимости от того, является ли числитель положительным, отрицательным или нулевым, соответственно.

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

Если вы пишете API (например, в библиотеке) и хотите предоставить контракт, который запрещает деление на ноль (например, он предоставляет метод, который выполняет какое-то деление), тогда вы можете захотеть выбросить это исключение ,Как правило, хотя, я бы зарезервировал этот тип исключения как индикатор программной ошибки.

1

Если вы пишете числовой класс какой-либо формы и можете ожидать, что код, вызывающий ваш класс, выполнил проверку, то я могу заметить, что это может оказаться полезным для исключения DivisionByZeroException, но почти в любом другом случае лучше проверить исключение операции и throw и ArgumentException или ArgumentOutOfRange.

NullReferenceException - одно из зарезервированных исключений, которое использует инфраструктура, которую вы никогда не должны запускать через открытый API, наряду с IndexOutOfRange, AccessViolationException и OutOfMemoryException. Смотрите книгу Руководства по проектированию Рамочного или Code Analysis warning explanation

+0

Спасибо. Я исправил вопрос (+1 для того, чтобы предупредить меня об этом). Я имел в виду «ArgumentNullException» – Armstrongest

+0

Если вы используете свой собственный индексный список, список, словарь, хеш-таблицу, что было бы неправильно с метанием «IndexOutOfRange» –

+0

Хорошая точка Matt – Armstrongest

0

Никогда (пользователь никогда не будет посылать 0 в знаменателе) и всегда (пользователь всегда будет предоставлять соответствующие значения аргументов) опасные идеи включить в своем коде. Очень маленький процент от нас программы в одиночку, по коду, который никогда не будет изменен или вызван другим разработчиком. Итак, нам нужно написать защитный код. В случае деления на ноль я не должен решать, каков должен быть соответствующий результат, который падает на вызывающего. Выброс исключения кажется разумным способом вернуть проблему. Хотя есть расходы, любая инфраструктура, которую я добавляю в свой код, чтобы избежать выброса исключения, также увеличивает расходы.

0

Если вы полагаетесь на фреймворк для выполнения работы (.NET или иначе), то вы должны позволить фреймворку исключить исключение.

Это позволит потребителям ваших методов обрабатывать исключения, которые выбрасываются стандартным образом.

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

Смежные вопросы