Другие ответы совершенно верны, но я думаю, что этот ответ дает некоторые дополнительные детали.
Рассмотрим этот пример:
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:\somepath\Program.cs:line 44
at Program.Main() in c:\somepath\Program.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:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 46
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
Это намного лучше, потому что теперь вы видите, что именно метод Program.Div
вызывал у вас проблемы. Но все еще трудно понять, возникает ли эта проблема из строки 35 или строки 37 в блоке try
.
Если вы используете третий вариант, заключая внешнее исключение, вы не теряете информацию:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 48
at Program.Main() in c:\somepath\Program.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:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 35
В частности, вы можете видеть, что строка 35 приводит к проблеме. Тем не менее, для этого требуется, чтобы люди искали InnerException
, и было бы несколько косвенным использовать внутренние исключения в простых случаях.
В этой записи блога они сохраняют номер строки (строку блока try), вызывая (через отражение) метод internal
intance InternalPreserveStackTrace()
объекта Exception
. Но не рекомендуется использовать такое отражение (.NET Framework может когда-нибудь изменить их internal
членов без предупреждения).