Pozostałe odpowiedzi są całkowicie poprawne, ale myślę, że ta odpowiedź zawiera dodatkowe szczegóły.
Rozważ ten przykład:
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);
}
}
Jeśli usuniesz komentarz z throw arithExc;
wiersza, wynikiem będzie:
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.
Z pewnością utraciłeś informacje o tym, gdzie zdarzył się ten wyjątek. Jeśli zamiast tego użyjesz throw;
linii, otrzymasz:
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.
Jest to o wiele lepsze, ponieważ teraz widzisz, że była to Program.Div
metoda, która spowodowała problemy. Ale nadal trudno jest sprawdzić, czy ten problem pochodzi z linii 35 czy linii 37 w try
bloku.
Jeśli użyjesz trzeciej alternatywy, zawierającej zewnętrzny wyjątek, nie stracisz żadnych informacji:
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
W szczególności widać, że to linia 35 prowadzi do problemu. Wymaga to jednak od ludzi przeszukiwania InnerException
i używanie pośrednich wyjątków w prostych przypadkach wydaje się nieco pośrednie.
W tym wpisie na blogu zachowują numer linii (wiersz bloku try), wywołując (poprzez odbicie) internal
metodę intencji InternalPreserveStackTrace()
na Exception
obiekcie. Ale nie jest miło używać takiego odbicia (.NET Framework może internal
pewnego dnia zmienić członków bez ostrzeżenia).