С# попробуйте уловить шаблон

Нам всегда нужно попробовать поймать в нашем коде, и он становится уродливым, как

public void foo()
{
  try
  {
    DoSomething();
  }
  catch(Exception e)
  {
     //do whatever with e
  }
}

public int FooReturnInt()
{
  try
  {
     return IntAfterSomeCalculation();
  }
  catch(Exception e)
  {
    //do exactly whatever with e as foo()
  }
}

Представьте, что у нас есть огромный класс с множеством общественных функций, подобных этому, и мы должны применять один и тот же try catch в каждой отдельной функции.

В идеале, поскольку часть catch try идентична, и мы можем передать параметр Func < > as вспомогательной функции, которая делает что-то вроде

public void TryCatch(Func<something> theFunction)
{
  try
  {
    theFunction();
  }
  catch(Exception e)
  {
    //processthe common exception        
  }
}

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

Ответ 1

Если вы действительно думаете, что это необходимо, вы можете использовать:

public T TryCatch<T>(Func<T> theFunction)
{
  try
  {
    return theFunction();
  }
  catch(Exception e)
  {
    // You'll need to either rethrow here, or return default(T) etc
  }
}

Однако я бы вообще советовал ему. Вы действительно уверены, что вам нужны блоки try/catch во всех этих методах? Как правило, не должно быть много блоков try/catch, если только catch не обертывает исключение и не отменяет... и даже это более редкое из С#, чем, например, в Java.

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

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

Ответ 2

Хотя вы можете использовать методы helper/wrapper, вы не должны структурировать свой код таким образом. Похоже, вы пытаетесь использовать try/catch, например, старую систему возвращенных кодов успеха/ошибок. Ваши публичные функции должны фактически бросать исключения соответствующего типа, и потребитель вашего API должен использовать try/catch на определенном уровне для управления исключительными условиями.

Механизм исключения try/catch был разработан для того, чтобы освободить разработчиков от необходимости комбинировать коды возврата из глубины кода, позволяя исключениям "просачивать" стек вызовов до тех пор, пока не будет найден обработчик. (Единственный раз, когда вы видите исключение, - это когда он не обрабатывается каким-либо методом в цепочке вызовов.) В любом случае здесь достойное место для начала по этой теме.

А вот "эмпирические правила" в блоге, которые будут легче переваривать, чем статья MSDN. И другая ссылка с еще более сокращенным контентом.

Выдержка из предыдущей ссылки:

  • Не поймать Исключения, с которыми вы не можете справиться
  • Никогда не проглатывайте исключения
  • В вашем коде должно быть больше Try/finally (или использования), чем Try/Catch
  • Никогда не бросайте/не захватывайте новое Exception() (слишком широкий класс), а пытайтесь thow\catch более производное исключение (ArgumentNullException и т.д.)
  • При повторном бросании исключения используйте throw; в отличие от броска ex; это будет сохранять трассировку стека reset
  • При написании библиотеки и приложения я никогда не поймаю если я не могу ОПРЕДЕЛЕННО обрабатывать его
  • Используйте логику для управления потоком программы, а не исключения, проверьте значение NULL, а не поймите ArgumentNullException

Номер 6 применяется непосредственно в вашей ситуации.

Ответ 3

Существует три причины использования блока catch:

1 Потому что может быть исключение.

Это неправильная причина.

2 Поскольку вы можете каким-то образом обработать исключение.

Это правильная причина.

3 Поскольку вы хотите добавить и/или скрыть данные

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

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

Ответ 4

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

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

Ответ 5

Вам действительно нужно ловить исключения во всех методах? Это нормально для метода для исключения исключений, если он обрабатывается "где-то".

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