Шаблон для отлова исключений из разделов кода (без кровотечения) - PullRequest
1 голос
/ 12 ноября 2009

У меня есть фрагмент кода, который выглядит следующим образом:

try
{
  classVar = functionCall(input, sEnum.First);

  classVar = functionCall(input, sEnum.Second);

  classVar = functionCall(input, sEnum.Third);
}
catch (Exception ex)
{
  Debug.Assert(false, ex.ToString());
}

Однако мое исключение не показывает, из какого именно звонка он пришел. Трассировка стека также показывает только детали из другого класса, вызываемого внутри вызова функции.

Альтернативный способ обернуть это:

try
{
  classVar = functionCall(input, sEnum.First);
}
catch (Exception ex)
{
  Debug.Assert(false, ex.ToString());
}
try
{
  classVar = functionCall(input, sEnum.Second);
}
catch (Exception ex)
{
  Debug.Assert(false, ex.ToString());
}
try
{
  classVar = functionCall(input, sEnum.Thrid);
}
catch (Exception ex)
{
  Debug.Assert(false, ex.ToString());
}

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

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

Ответы [ 7 ]

4 голосов
/ 12 ноября 2009

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

Вы можете сделать это, используя свойство StackTrace для исключения. Это позволит вам увидеть, где произошло исключение.

catch (Exception e) { 
    Console.WriteLine(e.StackTrace);
}

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

2 голосов
/ 12 ноября 2009

Номер строки в трассировке стека скажет вам, какой из трех был вызван.

2 голосов
/ 12 ноября 2009

Добавьте try / catch внутри метода functioncall () и также отладьте там. Если вам абсолютно необходимо, вы можете повторно сгенерировать исключение, чтобы передать его по цепочке к этому фрагменту кода.

1 голос
/ 12 ноября 2009

Вариант 1 Измените functionCall(), чтобы повторно выдать пользовательское исключение с контекстной информацией. Поймать исключение на более высоком уровне для регистрации, вызова Debug.Assert и т. Д.

Вариант 2 Этот шаблон может обеспечить повторное использование логики обработки исключений при небольшой потере читабельности. Осторожно: чрезмерное использование методов делегатов за счет ясности может стать запахом кода.

static void InvokeActionWithContext(Action action, string description) {
   try 
   {
     action();
   }
   catch(Exception ex)
   {
     throw new AnExceptionWithContext(description, ex);
   }
}

// call like this
InvokeActionWithContext( 
   () => classVar = functionCall(input, sEnum.Third),
   "Initializing value three"
);
1 голос
/ 12 ноября 2009

Как насчет написания вашего собственного класса исключений, который несет в качестве части своей полезной нагрузки значение enum? Вы также можете написать сообщение журнала, чтобы оно было более наглядным, чтобы вам не приходилось полагаться на трассировку стека, чтобы быть единственным источником информации.

0 голосов
/ 12 ноября 2009

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

    int step = 0;
    try
    {
       classVar = functionCall(input, sEnum.First);
       step++;

      classVar = functionCall(input, sEnum.Second);
      step++;

      classVar = functionCall(input, sEnum.Third);
   }
   catch (Exception ex)
   {
      //examine the step variable here

      Debug.Assert(false, ex.ToString());
   }
0 голосов
/ 12 ноября 2009

Это немного наивно, но ...

ExceptHandler<sEnum> h = new ExceptHandler<sEnum>();
try
{
  h.Step = sEnum.First;
  classVar = functionCall(input, sEnum.First);
  h.Step = sEnum.Second;
  classVar = functionCall(input, sEnum.Second);
  h.Step = sEnum.Third;
  classVar = functionCall(input, sEnum.Third);
}
catch (Exception ex)
{
  h.AssertException(ex.ToString());
}

ExceptHandler - это, по сути, конечный автомат, в котором хранится фактическое состояние, которое вы выполняете. Вы можете определить его как базовый класс, унаследованный от него для особых случаев ...

Отредактировано, чтобы сделать его более похожим на .NET:)

...