Как бороться с исключениями - PullRequest
2 голосов
/ 23 декабря 2008

Мой технический руководитель настаивает на этом механизме исключений:

try
{
    DoSth();
}
catch (OurException)
{
    throw;
}
catch (Exception ex)
{
    Util.Log(ex.Message, "1242"); // 1242 is unique to this catch block
    throw new OurException(ex);
}

1242 - это идентификатор метода catch, который обрабатывает исключение, отличное от OurException. Каждый блок catch в проекте должен иметь уникальный идентификатор, чтобы мы могли знать, где произошло исключение, просматривая журналы.

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

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

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

Edit2: Спасибо всем. Я использовал ваши ответы как часть моего аргумента против этого, но мне сказали, что вы недостаточно опытны и не знаете, как справляться с реальными жизненными ситуациями. Я должен идти этим путем.

Ответы [ 14 ]

5 голосов
/ 23 декабря 2008

Вы также можете просмотреть блок Приложение обработки исключений.

Я использовал его в нескольких проектах, и это очень полезно. Особенно, если вы хотите позже изменить работу вашей обработки исключений и какую информацию собирать.

3 голосов
/ 23 декабря 2008

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

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

try
{
DoSth();
}
catch(Exception ex)
{
Util.Log(ex.Message, ex.StackTrace);
if(ex is OurException) throw ex;
else throw new OurException(ex); // use the original exception as the InnerException
}

Кроме того, я не уверен, почему вы хотите выбросить исключение после того, как оно было обработано - вы можете объяснить причину этого?

@ Али А - Очень верный момент, поэтому позвольте мне перефразировать - зачем выбрасывать исключение, а не завершать его обработку прямо здесь?

EDIT:

Вместо того, чтобы бросить, почему бы не сделать это?

try
{
DoSth();
}
catch(Exception ex)
{
Util.HandleException(ex);
}

Util.HandleException:

public static void HandleException(ex)
{
Util.Log(ex); // Util.Log should log the message and stack trace of the passed exception as well as any InnerExceptions - remember, than can be several nested InnerExceptions.

// Any additional handling logic, such as exiting the application, or showing the user an error message (or redirecting in a web app)
}

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

2 голосов
/ 23 декабря 2008

Наличие OurException довольно странно. Обычно вы хотите иметь специализированные блоки перехвата, а затем последний, тот, который перехватывает универсальный Exception, где вы ведете запись:

try 
{
    DoSomething();
}
catch (DivideByZeroException)
{
    // handle it here, maybe rethrow it, whatever
}
// more catch blocks
catch (Exception)
{
    // oops, this is unexpected, so lets log it
}

Но то, что ты делаешь, сработает. Я действительно считаю, что 1242 должен идти. Вот метод для печати метода, имени файла и номера строки, которые вы могли бы использовать вместо этого. Я сам не пробовал, но выглядит хорошо:

    [Conditional("DEBUG")]
    public static void DebugPrintTrace()
    {
        StackTrace st = new StackTrace(true);
        StackFrame sf = st.GetFrame(1); // this gets the caller's frame, not this one
        Console.WriteLine("Trace "
            + sf.GetMethod().Name + " "
            + sf.GetFileName() + ":"
            + sf.GetFileLineNumber() + "\n");
    } 
1 голос
/ 24 декабря 2008

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

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

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

Экстремальный пример:

void a() {
  try {
    c();
  } catch(MyException1 ex) {
    throw;
  } catch(Exception ex) {
    log(ex);
    throw new MyException1(ex);
  }
}

void b() {
  try {
    a();
  } catch(MyException2 ex) {
    throw;
  } catch(Exception ex) {
    log(ex);
    throw new MyException2(ex);
  }
}

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

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

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

1 голос
/ 23 декабря 2008

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

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

0 голосов
/ 25 декабря 2008

Мое приложение построено в режиме выпуска, и я использую блок приложения обработки исключений, поэтому у меня никогда не было блоков кода catch ex, оно перехватывается EHAB, оно само записывает в файл журнала всю информацию я нуждаюсь; трассировка стека и т. д., время и т. д.

единственная проблема с этим, если кто-то поставил

catch ex
{
    //do stuff
    throw ex;
}

, поскольку это уничтожит трассировку стека.

0 голосов
/ 23 декабря 2008

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

0 голосов
/ 23 декабря 2008

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

0 голосов
/ 23 декабря 2008

Недостатки:

  1. Это число не внушает особой уверенности, трассировка стека намного лучше

  2. Зачем иметь 2 блока catch, если ваше пользовательское исключение может быть обработано на "catch (Exception ex) «

0 голосов
/ 23 декабря 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...