[C#] C #에서 예외를 잡아서 다시 던지는 이유는 무엇입니까?

직렬화 가능한 DTO 에 대한 기사 C #-데이터 전송 개체 를보고 있습니다.

이 기사에는 다음 코드가 포함되어 있습니다.

public static string SerializeDTO(DTO dto) {
    try {
        XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
        StringWriter sWriter = new StringWriter();
        xmlSer.Serialize(sWriter, dto);
        return sWriter.ToString();
    }
    catch(Exception ex) {
        throw ex;
    }
}

이 기사의 나머지 부분은 제정신이며 합리적으로 보이지만 try-catch-throw는 WtfException을 발생시킵니다. 예외를 전혀 처리하지 않는 것과 정확히 같지 않습니까?

에르고 :

public static string SerializeDTO(DTO dto) {
    XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
    StringWriter sWriter = new StringWriter();
    xmlSer.Serialize(sWriter, dto);
    return sWriter.ToString();
}

아니면 C #의 오류 처리에 대한 근본적인 내용이 누락 되었습니까? Java와 거의 동일하지만 (확인 된 예외 제외) 그렇지 않습니까? … 즉, 둘 다 C ++을 개선했습니다.

스택 오버플로 질문 매개 변수가없는 캐치를 다시 던지는 것과 아무것도하지 않는 것의 차이점은 무엇입니까? try-catch-throw가 절대 안된다는 내 주장을지지하는 것 같습니다.


편집하다:

미래 에이 스레드를 찾는 사람을 요약하면 …

하지 마라

try {
    // Do stuff that might throw an exception
}
catch (Exception e) {
    throw e; // This destroys the strack trace information!
}

스택 추적 정보는 문제의 근본 원인을 식별하는 데 중요 할 수 있습니다!

하다

try {
    // Do stuff that might throw an exception
}
catch (SqlException e) {
    // Log it
    if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
        // Do special cleanup, like maybe closing the "dirty" database connection.
        throw; // This preserves the stack trace
    }
}
catch (IOException e) {
    // Log it
    throw;
}
catch (Exception e) {
    // Log it
    throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
    // Normal clean goes here (like closing open files).
}

Java와 같이 덜 구체적인 예외보다 더 구체적인 예외를 포착하십시오.


참고 문헌 :



답변

먼저; 기사의 코드가 수행하는 방식은 사악합니다. throw ex이 throw 문이있는 지점으로 예외의 호출 스택을 재설정합니다. 예외가 실제로 생성 된 위치에 대한 정보가 손실됩니다.

둘째, 당신이 그렇게 잡아서 다시 던지면, 부가 가치가 없다는 것을 알 수 있습니다. 위의 코드 예제 throw ex는 try-catch 없이도 좋을 것입니다 (또는 비트가 더 좋았습니다).

그러나 예외를 잡아서 다시 던지는 경우가 있습니다. 로깅은 다음 중 하나 일 수 있습니다.

try
{
    // code that may throw exceptions    
}
catch(Exception ex)
{
    // add error logging here
    throw;
}


답변

이러지 마

try
{
...
}
catch(Exception ex)
{
   throw ex;
}

스택 추적 정보가 손실됩니다 …

어느 쪽이든

try { ... }
catch { throw; }

또는

try { ... }
catch (Exception ex)
{
    throw new Exception("My Custom Error Message", ex);
}

다시 던져야 할 이유 중 하나는 예를 들어 다른 예외를 처리하는 경우입니다.

try
{
   ...
}
catch(SQLException sex)
{
   //Do Custom Logging 
   //Don't throw exception - swallow it here
}
catch(OtherException oex)
{
   //Do something else
   throw new WrappedException("Other Exception occured");
}
catch
{
   System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
   throw; //Chuck everything else back up the stack
}


답변

C # (C # 6 이전)은 VB가 수행하는 CIL “필터링 된 예외”를 지원하지 않으므로 C # 1-5에서 예외를 다시 발생시키는 한 가지 이유는 catch () 시점에 충분한 정보가 없기 때문입니다. 실제로 예외를 잡을 것인지 결정합니다.

예를 들어 VB에서는

Try
 ..
Catch Ex As MyException When Ex.ErrorCode = 123
 ..
End Try

… 다른 ErrorCode 값으로 MyException을 처리하지 않습니다. v6 이전의 C #에서는 ErrorCode가 123이 아닌 경우 MyException을 포착하고 다시 발생시켜야합니다.

try
{
   ...
}
catch(MyException ex)
{
    if (ex.ErrorCode != 123) throw;
    ...
}

C # 6.0부터 VB와 마찬가지로 필터링 할 수 있습니다 .

try
{
  // Do stuff
}
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
  // Handle, other exceptions will be left alone and bubble up
}


답변

다음과 같은 코드를 사용하는 주요 이유는 다음과 같습니다.

try
{
    //Some code
}
catch (Exception e)
{
    throw;
}

캐치에 중단 점을 가질 수 있도록 인스턴스화 된 예외 객체가 있습니다. 개발 / 디버깅하는 동안 나는 이것을 많이한다. 물론 컴파일러는 사용되지 않은 모든 e에 대해 경고를 제공하며 이상적으로는 릴리스 빌드 전에 제거해야합니다.

그래도 디버깅하는 동안 좋습니다.


답변

예외를 다시 던지는 유효한 이유는 예외에 정보를 추가하거나 원래 예외 중 하나를 원래 예외로 래핑하기 때문일 수 있습니다.

public static string SerializeDTO(DTO dto) {
  try {
      XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
      StringWriter sWriter = new StringWriter();
      xmlSer.Serialize(sWriter, dto);
      return sWriter.ToString();
  }
  catch(Exception ex) {
    string message =
      String.Format("Something went wrong serializing DTO {0}", DTO);
    throw new MyLibraryException(message, ex);
  }
}


답변

이것은 예외를 전혀 처리하지 않는 것과 정확히 같지 않습니까?

정확히는 같지 않습니다. 예외의 스택 추적을 재설정합니다. 나는 이것이 아마도 실수이므로 잘못된 코드의 예라는 것에 동의하지만.


답변

당신은 ex를 던지고 싶지 않습니다-이것은 호출 스택을 잃을 것입니다. 예외 처리 (MSDN)를 참조하십시오 .

그리고 그렇습니다 .try … catch는 유용한 정보를 제공하지 않습니다 (콜 스택을 잃어 버리는 것을 제외하고는-어떤 이유로 든이 정보를 노출시키지 않으려는 경우가 아니라면 실제로 더 나쁩니다).