그 둘의 차이점이 이미 무엇인지 묻는 게시물이 있습니다.
(왜 이것을 언급해야합니까?)
그러나 내 질문은 다른 오류 신과 같은 처리 방법 에서 “throw ex”라고하는 방식이 다릅니다 .
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.
}
}
try & catch
에서 사용 된 경우 오류를 다시 발생시키는 데 Main
사용 throw;
합니다. 그러나 위의 간단한 코드에서 모든 예외는HandleException
합니까는 throw ex;
호출하는 것과 같은 효과가 throw
내부 전화했을 때를 HandleException
?
답변
예, 차이가 있습니다.
throw ex
스택 추적을 재설정합니다 (따라서 오류가 발생한 것으로 보입니다HandleException
)-
throw
하지 않습니다-원래 가해자가 보존됩니다.static void Main(string[] args) { try { Method2(); } catch (Exception ex) { Console.Write(ex.StackTrace.ToString()); Console.ReadKey(); } } private static void Method2() { try { Method1(); } catch (Exception ex) { //throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main) throw ex; } } private static void Method1() { try { throw new Exception("Inside Method1"); } catch (Exception) { 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>\Dev\UnitTester\Program.cs:line 49
at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19
Exception 2:
at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.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)
원래 stackTrace를 디버그 모드로만 유지합니까?
답변
다른 대답은 전적으로 정확하지만이 대답은 약간의 추가 detalis를 제공한다고 생각합니다.
이 예제를 고려하십시오.
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
문제를 일으키는 방법이라는 것을 알기 때문에 훨씬 좋습니다 . 그러나이 문제가 try
블록의 35 번째 줄 또는 37 번째 줄에서 오는지 여전히 확인하기 어렵습니다 .
외부 예외로 래핑하는 세 번째 대안을 사용하면 정보가 손실되지 않습니다.
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
언젠가 경고없이 멤버를 변경할 수 있습니다 ).
답변
던지기와 던지기의 차이점을 이해합시다. 많은 .net 인터뷰 에서이 일반적인 질문을 받고 있다고 들었습니다.
이 두 용어에 대한 개요를 제공하기 위해 throw 및 throw ex는 예외가 발생한 위치를 이해하는 데 사용됩니다. ex 예외는 실제로 발생한 위치에 관계없이 예외의 스택 추적을 다시 작성합니다.
예를 들어 이해합시다.
먼저 던지기를 이해합시다.
static void Main(string[] args) {
try {
M1();
} catch (Exception ex) {
Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
Console.WriteLine(ex.StackTrace.ToString());
Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
Console.WriteLine(ex.TargetSite.ToString());
}
Console.ReadKey();
}
static void M1() {
try {
M2();
} catch (Exception ex) {
throw;
};
}
static void M2() {
throw new DivideByZeroException();
}
위의 출력은 아래와 같습니다.
실제로 예외가 발생한 전체 계층 구조 및 메소드 이름을 표시합니다. M2-> M2입니다. 줄 번호와 함께
둘째로 .. 던져 전으로 이해합니다. M2 메서드 catch 블록에서 throw를 throw ex로 바꾸십시오. 아래.
ex ex 코드의 출력은 다음과 같습니다.
출력의 차이를 볼 수 있습니다. throw ex는 이전의 모든 계층 구조를 무시하고 throw ex가 작성된 행 / 방법으로 스택 추적을 재설정합니다.
답변
당신이 할 때 throw ex
, 그 예외는 “원래”가됩니다. 따라서 모든 이전 스택 추적이 존재하지 않습니다.
그렇게 throw
하면 예외가 줄을 넘어 전체 스택 추적을 얻습니다.
답변
아니요, 이로 인해 예외에 다른 스택 추적이 발생합니다. 에 throw
예외 개체없이 사용catch
핸들러 하면 스택 추적이 변경되지 않습니다.
예외가 다시 발생하는지 여부에 관계없이 HandleException에서 부울을 리턴 할 수 있습니다.
답변
MSDN의 약자 :
예외가 발생하면 전달되는 정보의 일부가 스택 추적입니다. 스택 추적은 예외를 발생시키는 메소드로 시작하여 예외를 포착하는 메소드로 끝나는 메소드 호출 계층 구조의 목록입니다. throw 문에 예외를 지정하여 예외가 다시 발생하면 현재 메서드에서 스택 추적이 다시 시작되고 예외를 발생시킨 원래 메서드와 현재 메서드 사이의 메서드 호출 목록이 손실됩니다. 원래 스택 추적 정보를 예외와 함께 유지하려면 예외를 지정하지 않고 throw 문을 사용하십시오.