Когда лучше бросить исключение, а когда лучше вернуть какой-нибудь журнал ошибок «объект»? - PullRequest
12 голосов
/ 18 апреля 2011

Мне было интересно, как выбрать между:

1) Если выбрасывать пользовательские исключения, ИЛИ

2) возвращать объект типа LOG, который имеет флаги, такие как 'CityNotFound,' 'ReferenceConstraintBroken'и т.д.

Я читал, что исключения дорогие.Если мне просто нужно знать конкретные детали результата процесса, для меня более выгодно иметь собственный «объект LOG процесса», который содержит только необходимую информацию о процессе.

Итак, если я вернусьна мой вопрос :

Когда лучше сгенерировать исключение, а когда лучше вернуть какой-нибудь журнал ошибок 'объект'?

Ответы [ 5 ]

16 голосов
/ 18 апреля 2011

Создайте исключение, чтобы предоставить дополнительную информацию (тип исключения, сообщение и т. Д.) Для правильной обработки и указать, что:

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

Я бы на самом деле не рекомендовал возвращать «объекты журнала» (т. е. возвращать объект исключения, а не выбрасывать его) как этот

  1. приводит к ненужным наборам операторов if для проверки результата и обработки потенциальной ошибки
    1. все ваши методы должны будут возвращать "объект журнала" (или иметь параметр out), иначе выне может "всплыть" из-за ошибки / исключения при обработке по областям, что приводит к дополнительным ограничениям
  2. теряет полезность try / catch / finally
  3. ухудшает читаемость области (попытка операции или обработка ошибок и очистка)

Если вы хотите вернуть «объекты журнала», вам следуетдействительно используйте логические возвраты с методами, которые имеют смысл (например, FindCity) или методами с out логическим параметром (например, TryFindCity).Таким образом, вам не нужно указывать флаги, а просто используйте методы, логический возврат которых позволяет вам определить значение потенциального флага.

EDIT

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

Если существуют валидационные зависимости, которые препятствуют «правильному разделению», тогда простобросьте один ValidationException с правильным аргументом (ами).Ниже приведен пример того, каким может быть этот класс:

public class ValidationException : Exception {
    private readonly object _Field;
    public object Field { get { return _Field; } }

    public ValidationException(string message) : base(message) { }

    public ValidationException(string message, object field)
        : this(message) {
        _Field = field;
    }
}

Затем вы можете просто выдать одно исключение, объясняющее ошибку проверки.

5 голосов
/ 18 апреля 2011

Если вас беспокоит производительность исключений, вы можете использовать шаблон «тестировщик», который в большинстве случаев можно использовать, чтобы избежать их (это также делает код более читабельным, чем попытка / отлов в мое мнение).

// Traditional try catch
try
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
catch (RecordNotFoundException)
{
    // The record not found in the database... what to do?
}

// Tester-doer pattern
if (myDb.myTable.RecordExists(primaryKey))
{
    var record = myDb.myTable.Select(primaryKey);

    // do something with record...
}
else
{
    // The record not found in the database... what to do?
}

Тот же результат, без исключений. Стоимость заключается в том, что вам нужно написать функцию «RecordExists» самостоятельно, обычно это будет так же просто, как сделать что-то вроде return COUNT FROM myTable WHERE PrimaryKey = foo == 1

3 голосов
/ 18 апреля 2011

Чтобы немного повернуть голову. Подумайте, знаю ли я, как справиться с этим условием внутри функции, и будет ли код вызываться достаточно часто, чтобы сделать его написание стоящим, или, в более общем смысле, это исключение?

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

2 голосов
/ 18 апреля 2011

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

Я бы никогда не вернул объект log.Это делает код нечитаемым, так как вы должны добавлять операторы if и специальную обработку везде.Лучше добавить такие методы, как CheckIfCityExists.

1 голос
/ 18 апреля 2011

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

Пример

  1. Вызов метода, чтобы проверить, найден ли город
  2. Перейдите к другим утверждениям
...