Когда Rethrow исключение в c#? - PullRequest
2 голосов
/ 02 апреля 2020

Я читал о том, почему мы должны бросить исключение и вернуть его. Но я запутался, когда Ретроу исключение? Я добавил пример, когда я помещаю throw в перехвате CalculationOperationNotSupportedException, и после этого я сравнил трассировку стека с Rethrowing и без Rethrowing. Это те же 99%, но когда вы отбрасываете исключение, оно просто добавляет местоположение. Конечно, если у вас точно два стека трассировки. Строка 35 - это номер «броска», а строка 28 - int result = calculator.Calculate (number1, number2, operation); Я думаю, что лучше использовать Stack Trace без повторного броска. Что вы думаете об этом?

Трассировка стека без повторного броска (выброс) Я прокомментировал это.

на ConsoleCalculator.Calculator.Calculate (Int32 number1, Int32 number2, Строковая операция) в C: \ Users \ Behnam \ Desktop \ c -sharp-error-processing-excptions \ 06 \ demos \ after \ 03UsingExceptions \ ConsoleCalculator \ Calculator.cs: строка 25 в ConsoleCalculator.Program. Main (String [] args) в C: \ Users \ Behnam \ Desktop \ c -sharp-error-обработка-исключений \ 06 \ demos \ after \ 03UsingExceptions \ ConsoleCalculator \ Program.cs: строка 28

Трассировка стека с повторным броском в улове (CalculationOperationNotSupportedException ex)

в ConsoleCalculator.Calculator.Calculate (Int32 номер1, Int32 номер2, операция String) в C: \ Users \ Behnam \ Desktop \ c -sharp-обработка ошибок-исключений \ 06 \ demos \ after \ 03UsingExceptions \ ConsoleCalculator \ Calculator.cs: строка 25 в ConsoleCalculator.Program.Main (String [] args) в C: \ Users \ Behnam \ Desktop \ * 10 28 * -sharp-обработка ошибок-исключений \ 06 \ demos \ after \ 03UsingExceptions \ ConsoleCalculator \ Program.cs: строка 35

public int Calculate(int number1, int number2, string operation)
{
    string nonNullOperation = 
        operation ?? throw new ArgumentNullException(nameof(operation));

    if (nonNullOperation == "/")
    {
        try
        {
            return Divide(number1, number2);
        }
        catch (ArithmeticException ex)
        {
            throw new CalculationException("An error occurred during division", ex);
        }
    }
    else
    {
        throw new CalculationOperationNotSupportedException(operation);
    }
}

static void Main(string[] args)
{
    var calculator = new Calculator();
    int number1=1;
    int number2=1;
    string operation = "+";
    try
    {
        int result = calculator.Calculate(number1, number2, operation);
        DisplayResult(result);
    }
    catch (CalculationOperationNotSupportedException ex)
    {
        // Log.Error(ex);
        WriteLine(ex);
        throw;
    }
}

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

Нет, ваше понимание того, как работает бросание и повторное бросание, неверно.

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

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

//Foo.cs
public class Foo
{
    public void Crash() => throw new Exception();
}

//Blah.cs
public class Blah
{
    public void CrashAndThrow()
    {
        var foo = new Foo();

        try 
        { 
            foo.Crash();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public void CrashAndReThrow()
    {
        var foo = new Foo();

        try 
        { 
            foo.Crash();
        }
        catch
        {
            throw;
        }
    }
}

//Program.cs
class Program
{
    static void Main(string[] args)
    {
        var bla = new Blah();
        try
        {
            bla.CrashAndThrow();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Throw:");
            Console.WriteLine(ex.StackTrace);
            Console.WriteLine();
        }

        try
        {
            bla.CrashAndReThrow();
        }
        catch (Exception ex)
        {
            Console.WriteLine("Rethrow:");
            Console.WriteLine(ex.StackTrace);
        }

        Console.ReadLine();
    }
}

Вывод этой программы на моем компьютере:

Throw:
   at SOStuff.Alpha.Blah.CrashAndThrow() in ...\SOStuff\Blah.cs:line 16
   at SOStuff.Program.Main(String[] args) in ...\SOStuff\Program.cs:line 13

Rethrow:
   at SOStuff.Alpha.Foo.Crash() in ...\SOStuff\Foo.cs:line 7
   at SOStuff.Alpha.Blah.CrashAndReThrow() in ...\SOStuff\Blah.cs:line 24
   at SOStuff.Program.Main(String[] args) in ...\SOStuff\Program.cs:line 24

Как вы можете видеть , когда вы бросаете, вся информация об оригинальном исключении, брошенном в Foo, теряется.

Общие правила, которые я применяю:

  1. Если вы не можете с этим справиться, дона не поймайте его
  2. Если вы не можете справиться с этим, но вам нужно поймать его, чтобы очистить, записать информацию или что-то еще, выбросить его.
  3. Если вы не можете справиться с этим, но нельзя допустить, чтобы чувствительная или не относящаяся к делу информация в исключении достигла потребителя, а затем выбросить новую с достаточным количеством информации, которая позволит впоследствии исправить ошибки.
  4. Если вы можете обработать ее, то обработайте ее .

99% времени, я применяю правило № 1.

1 голос
/ 02 апреля 2020

На тему есть две статьи c Я часто ссылаюсь. Я считаю их обязательными к прочтению.

На basi c, вы не должны ловить исключение, если не можете его обработать. Но иногда вы должны делать исключения (без каламбура) из любого правила об Исключении. Возможно, вам придется поймать шире, а затем применить «поймать и отпустить» к вашим дополнительным исключениям. Например, вот моя попытка повторной репликации TryParse:

//Parse throws ArgumentNull, Format and Overflow Exceptions.
//And they only have Exception as base class in common, but identical handling code (output = 0 and return false).

bool TryParse(string input, out int output){
  try{
    output = int.Parse(input);
  }
  catch (Exception ex){
    if(ex is ArgumentNullException ||
      ex is FormatException ||
      ex is OverflowException){
      //these are the exceptions I am looking for. I will do my thing.
      output = 0;
      return false;
    }
    else{
      //Not the exceptions I expect. Best to just let them go on their way.
      throw;
    }
  }

  //I am pretty sure the Exception replaces the return value in exception case. 
  //So this one will only be returned without any Exceptions, expected or unexpected
  return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...