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