c# 예제 - 예외 처리를 위해 try catch를 사용하는 것이 모범 사례입니다.




7 Answers

내 예외 처리 전략은 다음과 같습니다.

  • Application.ThreadException event 에 연결하여 처리되지 않은 모든 예외 를 catch하려면 다음을 결정하십시오.

    • UI 애플리케이션의 경우 : 사과 메시지 (winforms)를 사용하여 사용자에게 팝업합니다.
    • 서비스 또는 콘솔 응용 프로그램의 경우 : 파일 (서비스 또는 콘솔)에 기록하십시오.

그런 다음 try/catch 외부 에서 실행되는 모든 코드를 항상 포함합니다.

  • Winforms 인프라 스트럭처에 의해 발생 된 모든 이벤트 (로드, 클릭, SelectedChanged ...)
  • 제 3 자 구성 요소에 의해 시작된 모든 이벤트

그런 다음 'try / catch'

  • 내가 아는 모든 작업이 항상 작동하지 않을 수 있습니다 (IO 작업, 잠재적 제로 분할 계산 ...). 이러한 경우, 나는 새로운 ApplicationException("custom message", innerException) 을 던져 실제 일어난 일을 추적한다.

또한 예외를 올바르게 정렬하는 데 최선을 다합니다. 다음과 같은 예외가 있습니다.

  • 즉시 사용자에게 표시해야합니다.
  • 계단식 문제를 피할 때 상황을 맞추기 위해 몇 가지 추가 처리가 필요합니다 (예 : TreeView 채우기 중에 finally 섹션에 .EndUpdate 넣기)
  • 사용자는 신경 쓰지 않지만 무슨 일이 있었는지 아는 것이 중요합니다. 그래서 나는 항상 그것들을 기록한다.

    • 이벤트 로그
    • 또는 디스크의 .log 파일

응용 프로그램의 최상위 레벨 오류 핸들러에서 예외를 처리 할 수있는 정적 메서드설계 하는 것이 좋습니다.

나는 또한 다음과 같이 노력해야한다.

  • 모든 예외가 최상위 수준까지 버블 링된다는 것을 기억하십시오. 어디에서나 예외 처리기를 배치 할 필요는 없습니다.
  • 재사용 가능한 또는 깊은 호출 함수는 예외를 표시하거나 로그 할 필요가 없습니다. 자동 예외 처리는 예외 처리기에서 자동으로 버블 링되거나 사용자 정의 메시지와 함께 재발행됩니다.

그래서 마침내 :

나쁜:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

편치 않은:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

마침내 캐치없이 시도하면 완벽하게 유효합니다.

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

최상위 레벨에서 내가하는 일 :

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

일부 함수에서 내가하는 일 :

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

예외 처리 (Custom Exceptions)와는 많은 관계가 있지만 단순한 응용 프로그램에는 염두에 두어야 할 규칙이 있습니다.

다음은 catch 된 예외를 편안한 방법으로 처리하는 확장 메서드의 예입니다. 그들은 함께 묶을 수있는 방법으로 구현되며, 잡힌 예외 처리를 추가하는 것은 매우 쉽습니다.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}
예외처리 무시

수석 개발자라고 주장하는 사람조차도 동료 코드를 유지하면서 다음 코드를 자주 볼 수 있습니다.

try
{
  //do something
}
catch
{
  //Do nothing
}

또는 때로는 다음과 같이 로그 파일에 로깅 정보를 기록합니다. try catch 블록

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

그들이 한 일이 최선의 관행인지 궁금합니다. 내 생각에 사용자가 시스템에서 어떤 일이 일어나는지 알아야하기 때문에 혼란 스럽다.

제게 조언 해주세요.




예외는 블로킹 오류 입니다.

우선, 최선의 방법은 차단 오류가 아닌 한 어떤 종류의 오류에 대해서도 예외를 throw하지 말아야합니다 .

오류가 블로킹 중이면 예외를 throw하십시오. 예외가 이미 throw 된 후에는 예외이므로 숨길 필요가 없습니다. 사용자가 그것에 대해 알게하십시오 (UI에서 사용자에게 유용한 모든 예외를 다시 형식화해야합니다).

소프트웨어 개발자로서의 당신의 임무는 어떤 매개 변수 또는 런타임 상황이 예외적으로 끝날 수있는 예외적 인 경우 를 막기 위해 노력하는 것입니다. 즉, 예외는 음소거되어서는 안되지만 반드시 피해야 합니다.

예를 들어, 일부 정수 입력이 잘못된 형식을 가질 수 있다는 것을 알고 있으면 int.TryParse 대신 int.TryParse 를 사용 int.Parse . "실패하면 단순히 예외를 던지십시오"라고 말하는 대신에 이렇게 할 수있는 경우가 많이 있습니다.

예외를 던지면 비용이 많이 듭니다.

결국 예외가 발생하면 일단 예외가 발생하면 로그에 예외를 작성하는 대신 모범 사례 중 하나가 첫 번째 예외 처리기 에서이를 catch 합니다 . 예 :

  • ASP.NET : Global.asax Application_Error
  • 기타 : AppDomain.FirstChanceException 이벤트 입니다.

내 입장은 지역 try / catch가 예외를 다른 것으로 번역 할 수있는 특수한 경우를 처리하거나 또는 매우, 매우, 아주, 아주 특별한 경우에 대해 "음소거"하려는 경우에 적합하다는 것입니다 (라이브러리 버그 전체 버그를 해결하려면 음소거해야하는 관련없는 예외가 발생합니다.

나머지 경우 :

  • 예외를 피하십시오.
  • 이것이 가능하지 않은 경우 : 첫 번째 예외 처리기.
  • 또는 PostSharp aspect (AOP)를 사용하십시오.

일부 의견에 @thewhiteambit에 응답 중 ...

@thewhiteambit는 말했다 :

예외는 치명적 오류가 아니며 예외 사항입니다! 때로는 오류가 아니지만 오류를 고려해야합니다. 치명적 오류는 예외가 무엇인지에 대해 완전히 그릇된 이해입니다.

우선, 예외가 심지어 오류가 될 수없는 방법은 무엇입니까?

  • 데이터베이스 연결 => 예외가 없습니다.
  • 일부 유형 => 예외로 구문 분석 할 잘못된 문자열 형식
  • JSON 및 구문 분석을 시도하는 동안 실제로 JSON => 예외가 아닙니다.
  • 인수가 예상되었을 때의 인수는 null == 예외
  • 일부 라이브러리에는 버그 => 예기치 않은 예외가 발생합니다.
  • 소켓 연결이 끊어졌습니다. 그런 다음 메시지 => 예외를 보내려고합니다.
  • ...

예외가 발생했을 때의 1k 사례를 나열 할 수 있으며, 결국 오류가 발생할 수 있습니다.

하루가 끝날 때 진단 정보를 수집하는 객체이기 때문에 예외 발생합니다. 메시지가 있으며 문제가 발생하면 오류가 발생합니다.

예외적 인 경우가 없을 때 아무도 예외를 throw하지 않습니다. 예외가 발생하면 예외를 throw해야합니다. 제어 흐름을 구현하기 위해 try / catch 및 예외를 사용 하지 않으면 응용 프로그램 / 서비스가 예외적 인 경우에 입력 한 작업을 중지하게되므로 예외 를 차단해야합니다.

또한 Martin Fowler가 출판 한 fail-fast 패러다임 (Jim Shore 작성) 을 확인하는 것이 좋습니다. 이것은 내가 전에이 문서를 다루기 전에도 예외를 처리하는 방법을 항상 이해 한 방법입니다.

[...] 고려해보십시오. 치명적 오류는 예외가 무엇인지에 대해 완전히 그릇된 이해입니다.

일반적으로 예외 일부 작업 흐름을 줄이고 이를 처리하여 사람이 이해할 수있는 오류로 변환합니다. 따라서 예외 상황이 실제로 오류 사례를 처리하고 응용 프로그램 / 서비스 전체 충돌을 피하고 사용자 / 소비자에게 무언가가 잘못되었다는 사실을 알리는 작업을하는 더 나은 패러다임 인 것 같습니다.

@thewhiteambit 관심사에 대한 답변 더보기

예를 들어 데이터베이스 연결이 누락 된 경우 프로그램은 예외적으로 로컬 파일에 계속 쓰기를 수행하고 다시 사용할 수있게되면 데이터베이스에 변경 사항을 보냅니다. 잘못된 String-to-Number 캐스팅은 Exception에 대한 언어 로컬 해석으로 다시 구문 분석을 시도 할 수 있습니다. 예를 들어 Parse ( "1,5")로 기본 영어를 사용하면 실패하고 완전히 독일어 해석으로 다시 시도해보십시오 구분 기호로 점 대신 쉼표를 사용했기 때문에 문제가 없습니다. 이 예외는 차단되어서는 안되며 일부 예외 처리 만 필요합니다.

  1. 데이터베이스에 데이터를 유지하지 않고 앱이 오프라인으로 작동하는 경우 try/catch 사용하여 구현하는 제어 흐름을 안티 패턴으로 간주하므로 예외를 사용하지 않아야합니다. 오프라인 작업은 가능한 유스 케이스이므로 데이터베이스에 액세스 할 수 있는지 여부를 확인하기 위해 제어 흐름을 구현하므로 연결할 수 없을 때까지 기다리지 않아도 됩니다.

  2. 파싱 문제는 예상 사례이기도합니다 ( 예외 사례가 아님). 당신이 이것을 기대한다면, 당신은 제어 흐름을하기 위해 예외를 사용하지 않는다! . 사용자가 자신의 문화가 무엇인지 알기 위해 일부 메타 데이터를 얻고이를 위해 포맷터를 사용합니다. .NET은이 환경과 다른 환경도 지원합니다 . 응용 프로그램 / 서비스의 문화권 별 사용을 예상하는 경우 숫자 서식을 피해야하기 때문에 예외 입니다.

처리되지 않은 예외는 일반적으로 오류가되지만 예외 자체는 codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors가 아닙니다.

이 기사는 저자의 견해 또는 견해 일뿐입니다.

Wikipedia는 articule 저작자의 의견 일 수도 있기 때문에, 나는 그것이 교리 라고 말하지 않지만, 예외 조항에 의한 코딩이 어떤 절에서 어딘가에 있는지 확인하십시오.

[...] 이러한 예외를 사용하여 프로그램을 계속하기 위해 발생하는 특정 오류를 처리하는 것을 예외로 코딩이라고합니다. 이러한 안티 패턴은 소프트웨어의 성능과 유지 보수성을 빠르게 저하시킬 수 있습니다.

그것은 또한 어딘가에 말한다 :

잘못된 예외 사용

종종 예외로 코딩하면 잘못된 예외 사용으로 소프트웨어에 더 많은 문제가 발생할 수 있습니다. 고유 한 문제에 대해 예외 처리를 사용하는 것 외에도 잘못된 예외 사용은 예외가 발생한 후에도 코드를 실행하여 더 많이 사용합니다. 이 불쌍한 프로그래밍 방법은 많은 소프트웨어 언어에서 goto 방법과 유사하지만 소프트웨어의 문제가 감지 된 후에 만 ​​발생합니다.

솔직히, 나는 소프트웨어가 유스 케이스를 심각하게 생각하지 않고 개발할 수 없다고 생각한다. 네가 알면 ...

  • 데이터베이스가 오프라인이 될 수 있습니다 ...
  • 일부 파일을 잠글 수 있습니다 ...
  • 일부 서식이 지원되지 않을 수 있습니다 ...
  • 일부 도메인 유효성 검사가 실패 할 수 있습니다 ...
  • 앱이 오프라인 모드에서 작동해야합니다 ...
  • 사용 사례가 무엇이든지 ...

... 당신은 예외를 사용하지 않을 것입니다 . 정기적 인 제어 흐름을 사용하여 이러한 유스 케이스를 지원할 수 있습니다.

예상치 못한 사용 사례가 포함되지 않은 경우 예외가 발생 하므로 코드가 빨리 실패합니다. 예외는 예외적 인 경우 이기 때문에 그렇습니다 .

반면에 예외적 인 예외를 던지는 예외적 인 경우 를 다루기도하지만 제어 흐름을 구현하기 위해 예외를 던지지 않는 경우 도 있습니다. 어떤 유스 케이스를 지원하지 않거나 주어진 인자 나 환경 데이터 / 프로퍼티로 코드가 작동하지 않는다는 것을 상위 레이어에 알리고 싶기 때문에 그렇게한다.




나는 이것이 오래된 질문 인 것을 알고있다. 그러나 MSDN 기사를 언급 한 사람은 아무도 없다. MSDN 문서는 MSDN 문서에 나와있다. MSDN은 이것에 대한 아주 좋은 문서 를 가지고있다. 다음 조건이 참일 때 예외를 잡아야한다.

  • 예외가 발생하는 이유를 잘 알고 있으며 FileNotFoundException 객체를 catch 할 때 새 파일 이름을 입력하라는 메시지와 같이 특정 복구를 구현할 수 있습니다.

  • 좀 더 구체적이고 새로운 예외를 만들고 throw 할 수 있습니다.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • 추가 처리를 위해 예외를 전달하기 전에 부분적으로 예외를 처리하려고합니다. 다음 예에서 catch 블록은 예외를 다시 throw하기 전에 오류 로그에 항목을 추가하는 데 사용됩니다.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

전체 " 예외 및 예외 처리 "섹션과 예외 사례를 읽는 것이 좋습니다.




두 번째 방법은 좋은 방법입니다.

오류를 표시하고 관련없는 런타임 예외 (예 : 오류)를 표시하여 응용 프로그램 사용자를 혼동하지 않으려면 로그 오류 만 발생하면 기술 팀에서 문제를 찾아 해결할 수 있습니다.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

전체 애플리케이션에 대해 두 번째 접근법을 사용하는 것이 좋습니다.




나에게 예외 처리는 비즈니스 규칙으로 볼 수있다. 분명히 첫 번째 접근법은 받아 들일 수 없습니다. 두 번째 것은 더 나은 방법이며 문맥에 따라 100 % 올바른 방법 일 수도 있습니다. 이제는 예를 들어 Outlook Addin을 개발하고 있습니다. addin이 처리되지 않은 예외를 throw하면 outlook 사용자는 하나의 플러그인이 실패하여 Outlook 자체가 삭제되지 않으므로 이제이를 알 수 있습니다. 그리고 무엇이 잘못되었는지 파악하는 데 어려움이 있습니다. 따라서이 경우 두 번째 접근 방식은 제게는 올바른 것입니다. 예외 로깅 외에 사용자에게 오류 메시지를 표시하도록 결정할 수도 있습니다. 비즈니스 규칙으로 간주합니다.







때로는 사용자에게 아무 말도하지 않는 예외를 처리해야합니다.

내 길 :

  • 중요한 예외 (응용 프로그램이 유용 할 수 없음)에 대한 응용 프로그램 수준 (예 : global.asax)에서 오류없는 예외를 잡으려고하십시오. 이러한 exeptions 나는 장소에 잡히지 않을거야. 앱 레벨에서 로그 만하면 시스템이 제대로 작동합니다.
  • "장소에서"잡아서 사용자에게 유용한 정보를 보여줍니다 (잘못된 번호를 입력하고 구문 분석 할 수 없음).
  • 장소를 잡아라. "나는 백그라운드에서 업데이트 정보를 확인 하겠지만 서비스는 실행되고 있지 않다"와 같은 한계 문제에는 아무런 조치도 취하지 않는다.

확실히 모범 사례 일 필요는 없습니다. ;-)




Related

c# .net exception exception-handling try-catch