Бросить C # исключение того же типа, что и пойманный? - PullRequest
7 голосов
/ 05 октября 2010

почему (если вообще) это плохая идея?

class Program
{
  static void Main(string[] args)
  {
     try
     {
        throw new NotImplementedException("Oh dear");
     }
     catch (Exception ex)
     {
        throw NewException("Whoops", ex);
     }
  }

  // This function is the salient bit here
  public static Exception NewException(String message, Exception innerException)
  {
     return Activator.CreateInstance(innerException.GetType(), message, innerException) as Exception;
  }
}

Важным моментом здесь является то, что функция создает исключение того же типа, что и "innerException".

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

Речь может идти о какой-то ошибке SQL.Возможно, я не смогу обработать исключение в момент вызова, но, возможно, захочу добавить некоторую дополнительную «контекстную» информацию, например «Я звонил и передавал это».

Кажется, чтополезно передать обратно по цепочке вызовов исключение того типа, который был изначально создан, в отличие от «Exception» или «ApplicationException».Я знаю, что мог бы создавать свои собственные классы исключений, но, похоже, это ничего не добавляет, если у вас уже есть конкретное исключение.

Конечно, я могу ошибаться.Это может быть очень полезно, но небольшой голос подсказывает, что нет.

----- edit -----

Ради обсуждения рассмотримэффекты следующих двух функций (используя приведенный выше код):

Это ... видно слишком часто:

  static int SalesTotal(int customerNumber)
  {
     try
     {
        throw new DivideByZeroException(); // something you didn't expect
     }
     catch (Exception ex)
     {
        throw new ApplicationException("Unable to calculate sales for customer " + customerNumber, ex);
     }
  }

против этого ...

  static int SalesTotal(int customerNumber)
  {
     try
     {
        throw new DivideByZeroException(); // something you didn't expect
     }
     catch (Exception ex)
     {
        throw NewException("Unable to calculate sales for customer " + customerNumber, ex);
     }
  }

Ответы [ 7 ]

12 голосов
/ 05 октября 2010

все исключения имеют свойство Data, к которому можно добавить дополнительные данные.Нет необходимости создавать новое исключение.Просто перехватите существующее исключение и добавьте свою информацию, а затем просто сбросьте исключение.

Таким образом, вы получаете свой пирог и едите его тоже.:)

http://msdn.microsoft.com/en-us/library/system.exception_members(v=VS.90).aspx

4 голосов
/ 05 октября 2010

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

Создание нового исключения того же типа кажется опасным. Копирует ли используемая вами перегрузка CreateInstance все поля из innerException в ваше новое внешнее исключение? Что если обработчик исключений выше стека зависит от анализа свойства Message? Что если конструктор исключений имеет побочные эффекты?

ИМХО, что вы на самом деле делаете, это ведение журнала, и вам, вероятно, будет лучше на самом деле заняться ведением журнала и повторным броском.

3 голосов
/ 05 октября 2010

Я думаю, вы должны создать свой собственный тип исключений. Какую информацию вы собираетесь добавить? Как ловец исключения узнает, что у него есть дополнительная информация? Если вы используете пользовательский тип, они будут иметь дополнительные свойства / методы для просмотра или вызова.

1 голос
/ 05 октября 2010

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

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

0 голосов
/ 05 октября 2010

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

0 голосов
/ 05 октября 2010

ИМХО, вероятно, было бы хорошо иметь несколько пользовательских типов исключений, с одной иерархией для исключений, которые говорят: «Эта операция завершилась неудачно, но состояние системы такое, как если бы она никогда не предпринималась», другой для исключений, которые говорят: « Операция завершилась неудачно, и состояние системы было нарушено, но, вероятно, оно может быть размотано », а другой -« Операция завершилась неудачно, и размотка завершилась неудачей; состояние системы не может быть доверенным ». В некоторых контекстах один класс исключений может быть перехвачен и переброшен как другой (например, если операция, которая должна была завершить восстановление состояния системы, дает сбой, даже если с точки зрения этой операции ничего не было нарушено, сбой восстановления состояния может оставить его нарушенным, и наоборот, если операция оставила нарушенным состояние системы, но обработчик перехвата восстановил состояние, он может быть переброшен как «операция завершилась неудачно, но состояние системы не нарушено».

Мне очень не нравится идея создания экземпляров исключений, которые вслепую соответствуют выброшенным типам исключений, так как выброшенные исключения могут иметь поля, которые обработчики ожидают заполнить. Я не уверен, почему Microsoft сделала исключения «почти» неизменяемыми. Было бы гораздо приятнее, если бы исключения были неизменяемыми и поддерживали клонирование с любой семантикой, передающей неизменность.

0 голосов
/ 05 октября 2010

Это может иметь смысл в некоторых случаях. Если вы считаете MyClass.MyFunction общедоступной «снаружи» сборки, то то, что происходит внутри нее, является черным ящиком с вызывающим кодом. Поэтому может быть более разумным иметь это в качестве точки, в которой исключение произошло в том, что касается вызывающего кода, и наиболее разумным типом исключения может оказаться тот же тип, что и уловленный.

Я был бы осторожен, хотя. В большинстве случаев это происходило, либо вы должны были уловить, что должно произойти исключение, и выбрасывать превентивно (если вы собираетесь бросить, чем раньше, тем лучше), или же исключение, которое вы бросаете, нет ' Это действительно правильный тип (если ваш код не находит нужный ему файл, это исключение FileNotFoundException, но если файлы являются подробностями реализации, то это не исключение FileNotFoundException для вызывающего кода), иначе исходное исключение будет делать совершенный смысл, и ему просто нужно позволить звонить или перебрасывать с throw;.

Так что, это не всегда плохая идея, но достаточно часто плохая, и это всегда подозрительно.

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