何时在 C# 中重新引发异常?
Posted
技术标签:
【中文标题】何时在 C# 中重新引发异常?【英文标题】:When Rethrow a Exception in 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;
【问题讨论】:
***.com/questions/2493779/… 【参考方案1】:有两篇关于我经常链接的主题的文章。我认为它们是必读的。
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/ https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET基本上,如果您无法处理异常,则不应捕获它。但有时,您必须对有关异常的任何规则做出例外(不是双关语)。您可能必须更广泛地捕获,然后将“捕获和释放”应用于您获得的额外异常。例如,这是我在复制 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
中抛出的原始异常的所有信息都丢失了。
我应用的一般规则是:
-
如果你不能处理,不要抓住它
如果您无法处理它,但您需要捕获它以进行清理、记录信息或其他任何事情,请重新抛出它。
如果您无法处理它,但又不允许异常中的敏感或不适当的信息到达消费者,则抛出一个具有足够信息的新信息,以便以后进行正确调试。
如果你能处理它,那就处理它。
99% 的情况下,我都会应用规则 #1。
【讨论】:
以上是关于何时在 C# 中重新引发异常?的主要内容,如果未能解决你的问题,请参考以下文章