“扔”和“扔前”有区别吗?
有一些帖子询问这两者之间的区别是什么。
(为什么我不得不提到这一点...)
但是我的问题不同于我在另一个错误神般的处理方法中称之为“抛出”的方式。
public class Program
{
public static void Main(string[] args)
{
try
{
// something
}
catch (Exception ex)
{
HandleException(ex);
}
}
private static void HandleException(Exception ex)
{
if (ex is ThreadAbortException)
{
// ignore then,
return;
}
if (ex is ArgumentOutOfRangeException)
{
// Log then,
throw ex;
}
if (ex is InvalidOperationException)
{
// Show message then,
throw ex;
}
// and so on.
}
}
如果在Main
中使用try & catch
,那么我会使用throw;
重新抛出错误。 但是在上面简单的代码中,所有的异常都经过HandleException
throw ex;
在HandleException
调用throw
时有同样的效果吗?
是,有一点不同;
throw ex
重置堆栈跟踪(所以你的错误似乎源于HandleException
) throw
没有 - 原始的罪犯将被保留。 (我之前发布了,@Marc Gravell纠正了我)
以下是差异的演示:
static void Main(string[] args) {
try {
ThrowException1(); // line 19
} catch (Exception x) {
Console.WriteLine("Exception 1:");
Console.WriteLine(x.StackTrace);
}
try {
ThrowException2(); // line 25
} catch (Exception x) {
Console.WriteLine("Exception 2:");
Console.WriteLine(x.StackTrace);
}
}
private static void ThrowException1() {
try {
DivByZero(); // line 34
} catch {
throw; // line 36
}
}
private static void ThrowException2() {
try {
DivByZero(); // line 41
} catch (Exception ex) {
throw ex; // line 43
}
}
private static void DivByZero() {
int x = 0;
int y = 1 / x; // line 49
}
这里是输出:
Exception 1:
at UnitTester.Program.DivByZero() in <snip>DevUnitTesterProgram.cs:line 49
at UnitTester.Program.ThrowException1() in <snip>DevUnitTesterProgram.cs:line 36
at UnitTester.Program.TestExceptions() in <snip>DevUnitTesterProgram.cs:line 19
Exception 2:
at UnitTester.Program.ThrowException2() in <snip>DevUnitTesterProgram.cs:line 43
at UnitTester.Program.TestExceptions() in <snip>DevUnitTesterProgram.cs:line 25
您可以看到,在例外1中,堆栈跟踪会返回到DivByZero()
方法,而在例外2中则不会。
但请注意, ThrowException1()
和ThrowException2()
中显示的行号是throw
语句的行号, 而不是调用DivByZero()
的行号,现在我认为它可能是有意义的位...
在释放模式下输出
例外1:
at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)
例外2:
at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)
是否仅在调试模式下维护原始堆栈跟踪?
其他答案完全正确,但我认为这个答案提供了一些额外的问题。
考虑这个例子:
using System;
static class Program
{
static void Main()
{
try
{
ThrowTest();
}
catch (Exception e)
{
Console.WriteLine("Your stack trace:");
Console.WriteLine(e.StackTrace);
Console.WriteLine();
if (e.InnerException == null)
{
Console.WriteLine("No inner exception.");
}
else
{
Console.WriteLine("Stack trace of your inner exception:");
Console.WriteLine(e.InnerException.StackTrace);
}
}
}
static void ThrowTest()
{
decimal a = 1m;
decimal b = 0m;
try
{
Mult(a, b); // line 34
Div(a, b); // line 35
Mult(b, a); // line 36
Div(b, a); // line 37
}
catch (ArithmeticException arithExc)
{
Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);
// uncomment EITHER
//throw arithExc;
// OR
//throw;
// OR
//throw new Exception("We handled and wrapped your exception", arithExc);
}
}
static void Mult(decimal x, decimal y)
{
decimal.Multiply(x, y);
}
static void Div(decimal x, decimal y)
{
decimal.Divide(x, y);
}
}
如果你取消注释throw arithExc;
行,你的输出是:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:somepathProgram.cs:line 44
at Program.Main() in c:somepathProgram.cs:line 9
No inner exception.
当然,你已经失去了有关异常发生的信息。 如果你使用throw;
线,这是你得到的:
Handling a DivideByZeroException.
Your stack trace:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:somepathProgram.cs:line 58
at Program.ThrowTest() in c:somepathProgram.cs:line 46
at Program.Main() in c:somepathProgram.cs:line 9
No inner exception.
这样会好很多,因为现在你发现它是Program.Div
方法导致了你的问题。 但是仍然很难看到这个问题来自try
块中的第35行还是第37行。
如果您使用第三种替代方法,则封装在外部异常中,则不会丢失任何信息:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:somepathProgram.cs:line 48
at Program.Main() in c:somepathProgram.cs:line 9
Stack trace of your inner exception:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:somepathProgram.cs:line 58
at Program.ThrowTest() in c:somepathProgram.cs:line 35
特别是你可以看到它是导致这个问题的第35行 。 但是,这需要人们搜索InnerException
,并且在简单情况下使用内部异常感觉有点间接。
在此博客文章中,他们通过调用(通过反射) Exception
对象的internal
实例方法InternalPreserveStackTrace()
来保留行号(try块的行)。 但是使用这样的反射并不好(.NET框架有可能会在没有警告的情况下改变它们的internal
成员)。