"던지기"와 "던지기" 사이에 차이점이 있습니까?
벌써부터 그 둘의 차이점이 무엇인지 묻는 글들이 있습니다.
가 왜 까지 해야 거지...)
하지만 제 질문은 제가 다른 오류 신과 같은 취급 방법으로 "스로우 엑스"라고 부르는 점에서 다릅니다.
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; } }
(앞서 글을 올렸고, @Mark 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를 디버그 모드로만 유지합니까?
스로우는 스택 추적을 보존합니다.예를 들어 Source1이 Error1을 던지고 Source2가 Source1 Error + Source2 Error를 던지면 스택 추적에서 Source1 Error + Source2 Error를 사용할 수 있다고 합니다.
스로우 ex는 스택 추적을 보존하지 않습니다.따라서 Source1의 모든 오류는 삭제되고 Source2 오류만 클라이언트로 전송됩니다.
가끔 읽기만 해도 명확하지 않을 때가 있습니다. 이 비디오 데모를 보고 C#에서 Srow와 Srowex를 비교해 더 명확하게 이해하는 것이 좋습니다.
다른 답변들은 전적으로 옳지만, 이 답변은 추가적인 세부사항을 제공한다고 생각합니다.
이 예를 고려해 보십시오.
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;
line, 출력은다같습다니과입니다.
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
그리고 간단한 경우에 내부 예외를 사용하는 것은 다소 간접적으로 느껴집니다.
이 블로그 게시물에서 그들은 (반성을 통해) 전화를 걸어 라인 번호(시도 블록의 라인)를 유지합니다.internal
메소드 인턴스법스InternalPreserveStackTrace()
에서.Exception
건물▁. 사용하는( 하지만 그렇게 반사를 사용하는 것은 좋지 않습니다.가 NET Framework를 할 수 internal
회원들은 언젠가 예고 없이).
을 할 때는.throw ex
던져진 예외가 "원래" 예외가 됩니다.따라서 이전의 모든 스택 추적은 해당되지 않습니다.
네가 한다면.throw
예외는 라인을 따라 내려가고 전체 스택 추적을 얻을 수 있습니다.
던지기와 던지기의 차이점을 이해해 봅시다.많은 .net 인터뷰에서 이런 질문을 받고 있다고 들었습니다.
이 두 용어에 대한 개요를 제공하기 위해 예외가 발생한 위치를 파악하기 위해 스로우 및 스로우 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 메소드 캐치 블록에서 스로우를 스로우 ex로 교체하면 됩니다.
스로우 EX 코드의 출력은 아래와 같습니다.
출력의 차이를 확인할 수 있습니다.slow ex는 이전의 모든 계층 구조를 무시하고 slow ex가 기록된 line/syslog를 사용하여 스택 추적을 재설정합니다.
아니요, 이렇게 하면 예외의 스택 추적이 달라집니다.만 합니다.throw
인객체이에 가 있습니다.catch
처리기는 스택 추적을 변경하지 않고 유지합니다.
예외를 다시 적용할지 여부에 관계없이 HandleException에서 부울을 반환할 수 있습니다.
Microsoft Docs의 약자는 다음과 같습니다.
예외가 발생하면 해당 예외가 전달하는 정보의 일부는 스택 추적입니다.스택 추적은 예외를 발생시키는 메서드에서 시작하여 예외를 탐지하는 메서드로 끝나는 메서드 호출 계층의 목록입니다. 지외정예다에서 를 다시 던진
throw
명령문. 스택 추적이 현재 메서드에서 다시 시작되고 예외를 던진 원래 메서드와 현재 메서드 사이의 메서드 호출 목록이 손실됩니다.하려면 " " " " 을 합니다.throw
예외를 지정하지 않는 문입니다.
출처: https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2200
여기를 보세요: http://blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html
던지기:
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw;
}
예외가 있는 스택 정보를 보존합니다.
이를 "Retrow"라고 합니다.
새로운 예외를 던지고 싶다면,
throw new ApplicationException("operation failed!");
스로우 Ex:
try
{
// do some operation that can fail
}
catch (Exception ex)
{
// do some local cleanup
throw ex;
}
예외가 있는 스택 정보를 보내지 않음
이를 "스택 깨기"라고 합니다.
새로운 예외를 던지고 싶다면,
throw new ApplicationException("operation failed!",ex);
사용하는 것이 좋습니다.throw
에 throw ex
.
slow ex reset 원래 스택 추적을 다시 설정하여 이전 스택 추적을 찾을 수 없습니다.
스로우를 사용하면 전체 스택 추적을 얻을 수 있습니다.
이에 대한 다른 관점을 제공하기 위해 클라이언트에 API를 제공하는 경우 내부 라이브러리에 대한 자세한 스택 추적 정보를 제공하려는 경우에는 특히 throw를 사용하는 것이 유용합니다.여기에 스로우를 사용하면 시스템의 경우 스택 추적을 얻을 수 있습니다.IO.파일용 파일 라이브러리입니다.삭제합니다. 만약 제가 스로우 엑스를 사용한다면, 그 정보는 제 핸들러에게 전달되지 않을 것입니다.
static void Main(string[] args) {
Method1();
}
static void Method1() {
try {
Method2();
} catch (Exception ex) {
Console.WriteLine("Exception in Method1");
}
}
static void Method2() {
try {
Method3();
} catch (Exception ex) {
Console.WriteLine("Exception in Method2");
Console.WriteLine(ex.TargetSite);
Console.WriteLine(ex.StackTrace);
Console.WriteLine(ex.GetType().ToString());
}
}
static void Method3() {
Method4();
}
static void Method4() {
try {
System.IO.File.Delete("");
} catch (Exception ex) {
// Displays entire stack trace into the .NET
// or custom library to Method2() where exception handled
// If you want to be able to get the most verbose stack trace
// into the internals of the library you're calling
throw;
// throw ex;
// Display the stack trace from Method4() to Method2() where exception handled
}
}
루체로의 답변을 확장하기 위해, 원래 스택 추적을 잃지 않고 원래 코드의 의도를 달성할 수 있는 방법은 다음과 같습니다.
public class Program {
public static void Main(string[] args) {
try {
// something
} catch (Exception ex) {
if (!HandleException(ex)) throw;
}
}
/// <returns>
/// true if the exception has been handled;
/// false if exception should be passed along
/// </returns>
private static bool HandleException(Exception ex) {
if (ex is ThreadAbortException) {
// ignore then,
return true;
}
if (ex is ArgumentOutOfRangeException) {
// Log then,
return false;
}
if (ex is InvalidOperationException) {
// Show message then,
return false;
}
// and so on.
}
}
int a = 0;
try {
int x = 4;
int y ;
try {
y = x / a;
} catch (Exception e) {
Console.WriteLine("inner ex");
//throw; // Line 1
//throw e; // Line 2
//throw new Exception("devide by 0"); // Line 3
}
} catch (Exception ex) {
Console.WriteLine(ex);
throw ex;
}
모든 라인 1, 2 및 3에 주석이 달린 경우 - 출력 - 내부 ex
모든 라인 2와 3이 주석 처리된 경우 - 출력 - 내부 ex 시스템.DevideByZeroException: {"0으로 나누려고 했습니다."}---------
모든 라인 1과 2가 주석 처리된 경우 - 출력 - 내부 ex 시스템.예외: 0으로 나눗셈 ----
모든 라인 1과 3이 주석 처리된 경우 - 출력 - 내부 ex 시스템.DevideByZeroException: {"0으로 나누려고 했습니다."}---------
스로우 ex의 경우 StackTrace가 재설정됩니다.
언급URL : https://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex
'programing' 카테고리의 다른 글
jQuery UI 날짜 선택기 - 날짜 형식 변경 (0) | 2023.05.10 |
---|---|
로그캣이 안드로이드에서 아무것도 표시되지 않는 이유는 무엇입니까? (0) | 2023.05.10 |
전체 경로 없이 현재 디렉토리 또는 폴더 이름 가져오기 (0) | 2023.05.10 |
VB에서 #IF DEBUG를 사용하는 방법.그물 (0) | 2023.05.10 |
VBA 코드를 64비트 Windows와 호환되도록 하려면 어떻게 해야 합니까? (0) | 2023.05.10 |