Когда я должен использовать метод ThrowHelper вместо прямого броска?

когда целесообразно использовать ThrowHelper метод вместо бросать сразу?

void MyMethod() {
    ...
    //throw new ArgumentNullException("paramName");
    ThrowArgumentNullException("paramName");
    ...
}
void ThrowArgumentNullException(string paramName) {
    throw new ArgumentNullException(paramName);
}

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

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

во всяком случае, ИМО недостатки не являются иллюзорными тоже.

  • части (исключительных) поток управления скрыта
  • исключения в конечном итоге имеют более загадочный stacktrace
  • компилятор (2.0) не признает, что ThrowHelper вызовы являются точками выхода из метода, поэтому необходим некоторый код.

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

int MyMethod(int i) {
    switch (i) {
        case 1:
            return 1;
        default:
            ThrowMyException();
    }
    return 0; // Unreachable (but needed) code
 }

это может быть отчасти вопрос личного вкуса. В любом случае, каковы ваши личные рекомендации по этому вопросу? Считаете ли вы, что это хорошая идея использовать ThrowHelpers для всех этих общих задач, таких как проверка метода param (ThrowArgumentNullException (paramName) и такие)? Я упускаю что-то очевидное в этом вопросе?

кстати, я пытаюсь не смешивать эту проблему с проблема проверки, например, метод:

ThrowIfNameIsNullOrEmpty(name);

6 ответов


мой подход по умолчанию кидать напрямую от исключительных код филиала.

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

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

public void DoStuff(string stuff)
{
    // Do something

    throw this.CreateException("Boo hiss!");
}

private MyException CreateException(string message)
{
    return new MyException(message);
}

это сохраняет трассировку стека.


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

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

в основном абстрагирование от незначительных вещей, как это обычно возвращается, чтобы укусить вас. (Занимательное чтение на эту тему:http://www.joelonsoftware.com/articles/LeakyAbstractions.html)


Я бы сказал, что единственное разумное время для этого-это что-то вроде BCL, где объем использования класса достаточно широк, чтобы экономия стоила того. Однако в этом должен быть смысл. В твоем случае, я не думаю, что ты экономишь место. Примеры ThrowHelper в BCL уменьшите размер, заменив перечисления для строк и вызовов методов (для получения строковых сообщений). Вашем случае просто передает те же аргументы, и таким образом не достигните любых сбережений. Вызов вашего метода стоит столько же, сколько и создание исключения на месте.


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

Это мои 2 цента. Пожалуйста принимайте это как таковое.


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


одним из преимуществ, еще не упомянутых для использования метода throw-helper или exception-factory, является возможность передачи делегата для такой цели. При использовании делегата throw-helper появляется возможность не бросать (что в некоторых случаях было бы хорошо, а в других случаях-плохо). Например:

string TryGetEntry(string key, Funct<problemCause, string> errorHandler)
{
  if (disposed)
    return errorHandler(problemCause.ObjectDisposed);
  else if (...entry_doesnt_exist...)
    return errorHandler(problemCause.ObjectNotFound);
  else
    return ...entry...;
}
string GetEntry(string key)
{
  return TryGetEntry(key, ThrowExceptionOnError);
}
bool TryGetEntry(string key, ref result)
{
  bool ok;
  string result;
  result = TryGetEntry(key, (problemCause theProblem) => {ok=false; return (string)null;});
  return ok;
}

используя этот подход, можно легко использовать одну процедуру с различными стратегиями обработки ошибок. Можно было бы устранить необходимость в закрытии имея метод TryGetEntry принять параметр универсального типа вместе с параметром " ref "этого типа и делегатом, который принимает такой параметр "ref"; пример проще, хотя, просто используя закрытие.