programing

"던지기"와 "던지기" 사이에 차이점이 있습니까?

yellowcard 2023. 5. 10. 20:47
반응형

"던지기"와 "던지기" 사이에 차이점이 있습니까?

벌써부터 그 둘의 차이점이 무엇인지 묻는 글들이 있습니다.
가 왜 까지 해야 거지...)

하지만 제 질문은 제가 다른 오류 과 같은 취급 방법으로 "스로우 엑스"라고 부르는 점에서 다릅니다.

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를 비교해 더 명확하게 이해하는 것이 좋습니다.

던지기 vs 던지기 전

다른 답변들은 전적으로 옳지만, 이 답변은 추가적인 세부사항을 제공한다고 생각합니다.

이 예를 고려해 보십시오.

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);

사용하는 것이 좋습니다.throwthrow 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. 모든 라인 1, 2 및 3에 주석이 달린 경우 - 출력 - 내부 ex

  2. 모든 라인 2와 3이 주석 처리된 경우 - 출력 - 내부 ex 시스템.DevideByZeroException: {"0으로 나누려고 했습니다."}---------

  3. 모든 라인 1과 2가 주석 처리된 경우 - 출력 - 내부 ex 시스템.예외: 0으로 나눗셈 ----

  4. 모든 라인 1과 3이 주석 처리된 경우 - 출력 - 내부 ex 시스템.DevideByZeroException: {"0으로 나누려고 했습니다."}---------

스로우 ex의 경우 StackTrace가 재설정됩니다.

언급URL : https://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex

반응형