Класс обработки исключений - PullRequest
3 голосов
/ 07 апреля 2011

Какова лучшая практика для обработки исключений без необходимости помещать блоки try / catch везде?

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

Вот основная идея и реализация:

public class ExceptionHandler
{
    public static void Handle(Exception e)
    {
        if (e.GetBaseException().GetType() == typeof(ArgumentException))
        {
            Console.WriteLine("You caught an ArgumentException.");
        }
        else
        {
            Console.WriteLine("You did not catch an exception."); 
            throw e;   // re-throwing is the default behavior
        }
    }
}

public static class ExceptionThrower
{
    public static void TriggerException(bool isTrigger)
    {
        if (isTrigger)
            throw new ArgumentException("You threw an exception.");
        else
            Console.WriteLine("You did not throw an exception."); 
    }
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            ExceptionThrower.TriggerException(true); 
        }
        catch(Exception e)
        {
            ExceptionHandler.Handle(e);  
        }
        Console.ReadLine(); 
    }
}

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

Мысли?

Ответы [ 4 ]

6 голосов
/ 07 апреля 2011

ОК, возможно, это не тот ответ, который вам нужен, но ...

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

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

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

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

На самом деле есть веская причина, по которой вы не видите подобные конструкции в рабочем коде.

Прежде всего, такая конструкция не может помочь вам уменьшить количество try/ catch пар в вашем коде (это должно быть очевидно). может помочь вам сократить количество catch операторов для данного try, поскольку вы можете просто перехватить System.Exception и перейти к ExceptionHandler ...

Но что дальше?

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

  1. Получите из ExceptionHandler и поместите код для обработки исключений в виртуальные методы
  2. Передайте число Action<Exception> экземпляры к обработчику и вызовите его

Решение (1) будет хуже, чем у вас было раньше: теперь вам нужно создать целый новый класс для каждого блока try ипереопределите кучу методов, чтобы в итоге получить что-то на хуже , чем у вас было раньше (не сразу понятно, как код в определенном классе вписывается в поток вашей программы).Это также оставило бы другой важный вопрос без ответа: вам может понадобиться контекст (доступ к переменным в текущей области видимости), чтобы правильно обработать исключение.Как вы предоставите доступ к этому контексту?

Решение (2) на самом деле будет очень похоже на написание блоков catch, которых мы хотели бы избежать (каждый Action фактически будет содержимымcatch блока).В конечном итоге мы делаем то же самое, только более сложным и многословным образом.

Есть и другие проблемы:

  • Что должен сделать ExceptionHandler, если он не может обработать исключение?Бросив его еще раз, вы потеряете исходную трассировку стека, фактически уничтожив всю полезную информацию.
  • Что если в ExceptionHandler есть ошибка?Вы можете перефразировать try / catch.Можете ли вы доверять коду, который вы написали сами, в той же степени?

Что касается ExceptionThrower ... какое преимущество оно может предложить по сравнению с throw new Exception();?

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

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

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

Почему в вашем коде так много блоков try-catch? Можете привести несколько примеров? Исключения по самой своей природе "Исключительные", то есть не так часто! Вы не только не должны часто отлавливать исключения, но и каждое исключение, и тот же стандартный код, который работает в одной ситуации, вероятно, не подходит во многих других ситуациях.

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

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

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

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

Кроме того, блоки try / catch часто также включают в себя блок finally, в котором вы можете быть уверены, что все произойдет, даже если выдается исключение (например, закрытие потоков и т. Д.). У вас нет никакого способа договориться с этим.

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

...