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

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

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

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

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

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

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

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

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

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

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

Btw Я пытаюсь не смешивать эту проблему с проблемой проверки, например. например:

ThrowIfNameIsNullOrEmpty(name);
4b9b3361

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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'; пример проще, однако, просто используя закрытие.