【问题标题】:When Rethrow a Exception in c#?何时在 C# 中重新引发异常?
【发布时间】:2020-07-14 11:23:31
【问题描述】:

我已经阅读了为什么我们需要抛出异常并重新抛出它。但是我对何时重新抛出异常感到困惑?我在将 throw 放入 CalculationOperationNotSupportedException catch 时添加了一个示例,之后,我将 Stack Trace 与 Rethrowing 和不 Rethrowing 进行了比较。这是相同的 99%,但是当您重新抛出异常时,它只会添加位置。 当然,如果你准确地进行了两次堆栈跟踪。第 35 行是“抛出”位置编号,第 28 行是 int result = calculator.Calculate(number1, number2, operation); 我认为这里没有重新抛出的 Stack Trace 更好。你怎么看?

Stack Trace without rethrowing(throw) 我评论了它。

在 ConsoleCalculator.Calculator.Calculate(Int32 number1, Int32 number2,字符串操作)中 C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Calculator.cs:line 25 在 ConsoleCalculator.Program.Main(String[] args) 中 C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Program.cs:line 28

在 catch 中重新抛出堆栈跟踪(CalculationOperationNotSupportedException ex)

在 C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Calculator 中的 ConsoleCalculator.Calculator.Calculate(Int32 number1, Int32 number2, String operation) .cs:第 25 行 在 C:\Users\Behnam\Desktop\c-sharp-error-handling-exceptions\06\demos\after\03UsingExceptions\ConsoleCalculator\Program.cs:line 35 中的 ConsoleCalculator.Program.Main(String[] args) p>

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;
    }
}

【问题讨论】:

标签: c# exception


【解决方案1】:

有两篇关于我经常链接的主题的文章。我认为它们是必读的。

基本上,如果您无法处理异常,则不应捕获它。但有时,您必须对有关异常的任何规则做出例外(不是双关语)。您可能必须更广泛地捕获,然后将“捕获和释放”应用于您获得的额外异常。例如,这是我在复制 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;
}

【讨论】:

    【解决方案2】:

    不,您对投掷和重投原理的理解不正确。

    当您抛出异常时,您会丢失在新抛出异常之前发生的所有堆栈跟踪信息。问题是您将所有代码都放在同一个文件中,并且您在读取和正确比较每个堆栈跟踪中的信息时遇到问题。

    构建以下代码,确保每个类都位于不同的 .cs 文件中。运行它并比较两个打印的堆栈跟踪,你会看到 throwing 丢失了信息:

    //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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 2016-01-15
      • 1970-01-01
      • 2012-07-16
      • 2012-01-13
      • 2013-02-05
      • 2016-03-18
      相关资源
      最近更新 更多