Исключения: инкапсулировать их или нет?

Однажды я прочитал статью в MSDN, которая поощряла следующую парадигму программирования (это не на 100% верно... см. Редактирование):

public class MyClass
{
    public void Method1()
    {
        NewCustomException();
    }

    public void Method2()
    {
        NewCustomException();
    }

    void NewCustomException()
    {
        throw new CustomException("Exception message");
    }
}

Как вы думаете, эта парадигма имеет смысл? Разве этого недостаточно, чтобы сохранить сообщение об исключении в static const поле, а затем передать его конструктору исключения, вместо инкапсуляции целого исключения throw?

РЕДАКТИРОВАТЬ:

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

Я только что заметил (см. Цитату), что в статье сказано возвращать исключение:

public class MyClass
{
    public void Method1()
    {
        throw NewCustomException();
    }

    public void Method2()
    {
        throw NewCustomException();
    }

    CustomException NewCustomException()
    {
        return new CustomException("Exception message");
    }
}

Что Вы думаете об этом?

7 ответов

Решение

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

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

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

    public string GetFoo1(bool bar)
    {
        if (bar)
            return "";
        else
            NewCustomException();
    }

    public string GetFoo2(bool bar)
    {
        if (bar)
            return "";
        else
            throw new CustomException("Exception message");
    }

GetFoo1 не будет компилироваться, в то время как GetFoo2 будет.

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

С помощью этого метода, если вы хотите изменить тип исключения по какой-либо причине, вам нужно сделать это только в одном месте (например, изменить ConfigurationException в ConfigurationErrorsException при обновлении с.NET 1.x до.NET 2.0).

Также вы уважаете принцип СУХОГО, имея единственную копию кода, который создает исключение с его сообщением и любыми другими данными, включенными в исключение.

Вы, очевидно, не будете делать это в тривиальных случаях (например, вы не замените throw new ArgumentNullException("myParamName") от throw BuildArgumentNullException("myParamName"))

private static Exception BuildSomeException(... parameters with info to include in the exception ...)
{
    string message = String.Format(...);
    return new SomeException(message, ...);
}

...
throw BuildSomeException(...);

Это удобно, если вы точно не знаете, как планируете обрабатывать исключения. Вы хотите просто бросить это? Или, может быть, позже вы где-нибудь зарегистрируете исключение, а затем выбросите его? Или, может быть, передать некоторые аргументы (например, имя метода и т. Д.), Которые включаются в исключение?

В этом случае создание отдельного метода, который обрабатывает исключительную ситуацию, удобно, если вы хотите изменить его.

Обычно я не беспокоюсь об этом - вместо этого просто заранее выясните, как вы собираетесь обрабатывать исключения (то есть, какую строковую информацию вы собираетесь поместить в сообщение).

Я обычно предпочитаю хранить сообщения об исключениях в качестве ресурсов. Это служит нескольким целям:

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

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

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

Другие вопросы по тегам