Подтвердить что ты не робот

Общая стратегия обработки исключений для .NET.

Мне приходилось использовать блоки try/catch в каждом методе. Причина этого в том, что я могу поймать каждое исключение в момент нарушения и зарегистрировать его. Я понимаю, из моего чтения и бесед с другими, что это не популярное мнение. Нужно только поймать то, что готово обрабатывать. Однако, если я не поймаю на месте нарушения, тогда можно будет никогда не регистрировать это нарушение и не знать об этом. Примечание: Когда я поймаю и не обрабатываю, я все равно бросаю. Это позволяет мне допускать, чтобы исключение распространялось на то, что будет обрабатывать его, но все же позвольте мне зарегистрировать его в точке нарушения.

Итак... Как избежать try/catch в каждом методе, но все же регистрировать ошибку в той точке, в которой она произошла?

4b9b3361

Ответ 1

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

Это означает, например, что вы должны окружить код обработчика события блоком try/catch. Обработчик событий может быть "вершиной стека". То же самое для обработчика ThreadStart или обратного вызова из асинхронного метода.

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

В случае ASP.NET вы можете разрешить администратору ASP.NET Health Monitoring регистрировать для вас исключение.

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

Ответ 2

Вы можете видеть все на трассе стека - нет необходимости пытаться/улавливать каждый метод.

Придерживайтесь нескольких правил:

  • Используйте try/catch только в том случае, если вы хотите использовать настраиваемый тип исключения
  • Определите новый тип исключения, только если верхние уровни должны знать, что
  • Попробуйте/поймать на верхнем уровне вместо того, чтобы делать это для каждого метода

Ответ 3

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

Я бы не поставил try/catch в каждом методе, далеко от него. Но я бы использовал try/catch вокруг разделов кода, которые я ожидал сбой (например, открытие файла), и где я хотел добавить дополнительную информацию к исключению (чтобы быть зарегистрированным выше в цепочке).

Высказывание трассировки стека и сообщение с "разрешенным разрешением" могут быть достаточно, чтобы позволить вам как программисту понять, что пошло не так, но моя цель - предоставить пользователю значимую информацию, такую ​​как "Не удалось открыть файл 'C:\lockedfile.txt'. Permission denied.".

Как в:

private void DoSomethingWithFile(string filename)
{
    // Note: try/catch doesn't need to surround the whole method...

    if (File.Exists(filename))
    {
        try
        {
            // do something involving the file
        }
        catch (Exception ex)
        {
            throw new ApplicationException(string.Format("Cannot do something with file '{0}'.", filename), ex);
        }
    }
}

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

Ответ 4

Чтобы сделать это в момент появления, вам все равно понадобится try/catch. Но вы не обязательно должны ломать исключения во всем мире. Они распространяют стек вызовов, и когда они пойманы, вы получаете трассировку стека. Поэтому, если проблема возникает, вы всегда можете добавить больше попыток/уловов по мере необходимости.

Рассмотрите возможность проверки одной из многих доступных фреймворков ведения журнала.

Ответ 5

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

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

Конечно, просто повторюсь, увеличивая свои исключения до вершины и регистрируя stacktrace - это лучший подход, чем блокирование блоков try-catch-log-throw по всему вашему коду.

Ответ 6

Я бы рассмотрел использование ELMAH для обработки исключений, что в значительной степени является концепцией "пусть исключения происходят". ELMAH позаботится о их регистрации, и вы даже можете настроить его для отправки по электронной почте, когда исключения для определенного проекта превышают определенный предел. В моем отделе мы находимся как можно дальше от блоков try/catch. Если что-то не так в приложении, мы хотим сразу знать, в чем проблема, поэтому мы можем исправить это, вместо того, чтобы подавлять исключение и обрабатывать его в коде.

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

И никогда, никогда, никогда не поймайте общее исключение. Всегда, всегда, всегда выбирайте наиболее конкретное исключение, чтобы, если генерируется исключение, но это не тот тип, который вы ожидаете, снова вы узнаете, потому что приложение будет аварийно. Если вы просто поймаете (Exception e), то независимо от того, какой тип исключения будет выброшен, ваш блок catch теперь будет отвечать за ответ на каждый отдельный тип исключения, который можно было бы выбросить. И если это не так, тогда вы сталкиваетесь с целыми "пищевыми" исключениями, где что-то идет не так, но вы никогда не узнаете, пока не станет слишком поздно.

Ответ 7

Как избежать try/catch в каждом методе, но все же регистрировать ошибку в той точке, в которой она произошла?

Это зависит от хостинга. Asp.Net, WinForms и WPF имеют разные способы захвата необработанных исключений. Но как только глобальный обработчик проходит экземпляр исключения, вы можете определить точку броска из исключения, поскольку каждое исключение включает в себя стек.

Ответ 8

  • Захват и повторное исключение, которое вы не можете обработать, - это не что иное, как потеря времени процессора. Если вы не можете ничего сделать с исключением или исключение, проигнорируйте его и позвольте вызывающему абоненту ответить на него.
  • Если вы хотите регистрировать каждое исключение, глобальный обработчик исключений будет работать отлично. В .NET трассировка стека является объектом; его свойства можно проверять, как и любые другие. Вы можете записать свойства трассировки стека (даже в строковой форме) в ваш журнал выбора.
  • Если вы хотите, чтобы все исключения были пойманы, глобальный обработчик исключений должен сделать трюк. На самом деле ни одно приложение не должно быть без него.
  • Ваши блоки catch должны только ловить исключения, которые, как вы знаете, можете изящно восстановить. То есть, если вы можете что-то сделать, поймите. В противном случае позвольте вызывающему беспокоиться об этом. Если ни один из вызывающих абонентов ничего не может с этим поделать, пусть глобальный обработчик исключений поймает его и зарегистрирует.

Ответ 9

Я определенно не использую обертку try catch для каждого метода (как это ни странно, я делал это при первом запуске, но это было до того, как я узнал, что лучше).

1) Чтобы предотвратить сбой программы и пользователи теряют информацию, я делаю это

                runProgram:
                try
                {
                    container.ShowDialog();
                }
                catch (Exception ex)
                {
                    ExceptionManager.Publish(ex);
                    if (MessageBox.Show("A fatal error has occurred.  Please save work and restart program.  Would you like to try to continue?", "Fatal Error", MessageBoxButtons.YesNo) == DialogResult.Yes)
                        goto runProgram;
                    container.Close();
                }

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

2) Я только перехватываю исключения в методах, когда ожидаю, что что-то может пойти не так (например, таймаут).

3) Точно так же, как точка читаемости, если у вас есть блок catch try с кучей кода в разделе try и связкой в ​​секции catch, лучше извлечь этот код в хорошо подобранный метод.

   public void delete(Page page) 
   {
      try 
      {
         deletePageAndAllReferences(page)
      }
      catch (Exception e) 
      {
         logError(e);
      }
   }

Ответ 10

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

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

Ответ 11

Исключения выполняются так, что они не имеют никакой стоимости, кроме брошенных.

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