Разница между повторным бросанием параметра без улова и ничего не делает?

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

//in assembly A
public class TypeA {
   // Constructor omitted
   public void MethodA
   {
     try {
       //do something
     }
     catch {
        throw;
     }
   }
}
//in assembly B
public class TypeB {
   public void MethodB
   {
     try {
       TypeA a = new TypeA();
       a.MethodA();
     }
     catch (Exception e)
       //Handle exception
     }
   }
}

В этом случае try-catch в MethodA просто повышает исключение, но не справляется с этим. Есть ли преимущество в использовании try-catch вообще в MethodA? Другими словами, существует ли разница между этим типом блока try-catch и вообще не используется?

Ответ 1

В вашем примере это не имеет никакого преимущества. Но бывают случаи, когда желательно просто создать конкретное исключение.

    public void Foo()
    {
        try
        {
            // Some service adapter code

            // A call to the service
        }
        catch (ServiceBoundaryException)
        {
            throw;
        }
        catch (Exception ex)
        {
            throw new AdapterBoundaryException("some message", ex);
        }
    }

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

Ответ 2

Да, есть разница. Когда вы поймаете исключение,.NET предполагает, что вы каким-то образом обработаете его, стек разматывается до функции, выполняющей catch.

Если вы его не поймаете, это станет необработанным исключением, которое вызовет какую-то диагностику (например, отладчик или регистратор исключений), будет доступен полный стек и его состояние в фактической точке сбоя для проверки.

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

Ответ 3

Взятый как есть, первый вариант будет казаться плохим (или должен быть "бесполезным"?) идеей. Однако это редко делается так. Исключения повторно выбрасываются из блока Catch обычно в двух условиях:

а. Вы хотите проверить исключение, сгенерированное для данных, и условно вывести его в стек.

try 
{
  //do something
}
catch (Exception ex)
{
  //Check ex for certain conditions.
  if (ex.Message = "Something bad")
    throw ex;
  else
    //Handle the exception here itself.
}

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

try 
{
  //do something
}
catch (StackOverflowException ex)
{
    //Bubble up the exception to calling code 
    //by wrapping it up in a custom exception.
    throw new MyEuphemisticException(ex, "Something not-so-good just happened!");
}

Ответ 4

С кодом, как вы его написали для MethodA, нет никакой разницы. Все, что он будет делать, это съесть процессорные циклы. Однако может быть преимущество в написании кода таким образом, если есть ресурс, который вы должны освободить. Например

Resource r = GetSomeResource();
try {
  // Do Something
} catch { 
  FreeSomeResource();
  throw;
}
FreeSomeResource();

Однако нет реального смысла в этом. Было бы лучше просто использовать блок finally.

Ответ 5

Просто ретронирование не имеет смысла - это так же, как если бы вы ничего не делали.

Однако он становится полезным, когда вы на самом деле что-то делаете - наиболее распространенная вещь - регистрировать исключение. Вы также можете изменить состояние своего класса, независимо от того, что.

Ответ 6

Никогда не делайте вариант A. Как говорит Антон, он съедает трассировку стека. Пример JaredPar также поглощает стек. Лучшим решением будет:

SomeType* pValue = GetValue();
try {
  // Do Something
} finally {
  delete pValue;
}

Если у вас есть что-то в С#, которое нужно отпустить, например FileStream, у вас есть следующие два варианта:

FileStream stream;
try
{
  stream = new FileStream("C:\\afile.txt");
  // do something with the stream
}
finally
{
  // Will always close the stream, even if there are an exception
  stream.Close(); 
}

Или более чисто:

using (FileStream stream = new FileStream("c:\\afile.txt"))
{
  // do something with the stream
}

Использование инструкции будет удалять (и закрывать) поток по завершении или когда исключение закрывается.

Ответ 7

Когда вы ловите и бросаете, это позволяет вам установить точку останова в строке throw.

Ответ 8

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

public class XmlException: Exception{
   ....
} 

public class XmlParser{
   public void Parse()
   {
      try{
          ....
      }
      catch(IOException ex)
      {
         throw new XmlException("IO Error while Parsing", ex );
      }
   }
}

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

Ответ 9

Блок сборки A - try catch не имеет для меня никакого смысла. Я считаю, что если вы не собираетесь обрабатывать исключение, то почему вы перехватываете эти исключения.. Это было бы все равно брошено на следующий уровень.

Но если вы создаете API-интерфейс среднего уровня или что-то в этом роде и обрабатываете исключение (и, следовательно, есть исключение) в этом слое, это не имеет смысла, тогда вы можете бросить свой собственный класс ApplicationException. Но, безусловно, повторение одного и того же исключения не имеет смысла.

Ответ 10

Поскольку классы находятся в двух разных сборках, вам может понадобиться o просто поймать исключение для его регистрации, а затем выбросить обратно вызывающему, чтобы он мог обрабатывать его так, как он считает нужным. Бросок вместо throw ex сохранит контекстуальную информацию о том, откуда возникло исключение. Это может оказаться полезным, когда ваша сборка является API/фреймворком, где вы никогда не должны проглатывать исключения, если это не имеет смысла делать это, но полезно, тем не менее, при устранении проблем, если он регистрируется, например, в EventLog.

Ответ 11

Вы можете использовать блок try {} catch (ex) {} в методе A, только если вы можете поймать конкретное исключение, которое может обрабатываться в MethodA() (например, для ведения журнала).

Другой вариант - это цепочка исключений с использованием свойства InnerException и передать его вызывающему. Эта идея не будет убивать трассировку стека.