try / catch + 사용하여 올바른 구문


189

어느 것:

using (var myObject = new MyClass())
{
   try
   {
      // something here...
   }
   catch(Exception ex)
   {
      // Handle exception
   }
}

또는

try
{
   using (var myObject = new MyClass())
   {
      // something here...
   }
}
catch(Exception ex)
{
   // Handle exception
}

7
참고 : 로깅 또는 래핑을 제외하고 실제로 처리 (수정) 할 수있는 예외 만 포착하도록주의해야 합니다.
John Saunders

1
또한 지난 것을 명심하시기 바랍니다 }using문은 예외를 던질 수있는 여기 연상으로 .
Giulio Caccin

1
첫 번째 코드 블록을 사용하는 경우 디버거 (VS에서)가 dispose 메서드를 호출하지 않도록 TIL합니다. using 문 자체가 예외를 throw 할 수 있기 때문에 두 번째 블록을 사용하여 암시 적 finallydispose 메서드라고하는 데 도움이 됩니다.
ShooShoSha

답변:


98

나는 두 번째를 선호합니다. 객체 생성과 관련된 오류도 잡을 수 있습니다.


11
이 조언에 동의하지 않습니다. 객체 생성시 오류가 발생할 것으로 예상되는 경우 해당 예외 처리는 외부로 진행 되어야합니다 . 처리가 어디로 가야하는지에 대한 의문이있는 경우 예상되는 예외는 예상 할 수 있거나 예상하지 못한 임의의 예외를 잡는 것을 옹호하지 않는 한 예상되는 예외입니다. 프로세스 또는 스레드의 처리되지 않은 예외 처리기).
Jeffrey L Whitledge

1
@ Jeffrey : 내가 설명 한 접근 방식이 나에게 도움이되었으며 오랫동안 이것을 해왔습니다. 아무도 대해 아무것도 말했다 기대 객체 생성이 실패합니다. 그러나 수있는 동작을 포장하여 잠재적 A의 실패 try뭔가가 실패하면 오류 메시지가 팝업 할 수 있도록 블록을, 프로그램은 이제 복구하고 사용자에게 알려주는 기능이 있습니다.
조나단 우드

귀하의 답변은 정확하지만 시도 / 캐치 항상 (즉시) 있어야 한다는 제안을 계속합니다 .
Henk Holterman

17
첫 번째 장점도 있다고 생각 using( DBConnection conn = DBFactory.getConnection())합니다. 예외가 발생한 경우 롤백 해야하는 DB 트랜잭션 을 고려하십시오 . 둘 다 자신의 자리를 가지고있는 것 같습니다.
양육

1
또한 객체 처리 와 관련된 오류를 포착 합니다.
Ahmad Ibrahim

39

using 블록은 try / finally ( MSDN ) 의 구문 단순화 일 뿐이므로 개인적으로 다음을 수행 할 것입니다.하지만 두 번째 옵션과는 크게 다릅니다.

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}

4
문장 finally보다 블록을 추가하는 것이 왜 더 좋다고 생각 using합니까?
코디 그레이

10
finallyIDisposable 객체를 처리 하는 블록을 추가하면 using명령문이 수행됩니다. 개인적으로, 나는 using모든 것이 일어나는 곳을 더 명확하게 설명하고 모두 같은 "레벨"에 있다고 생각하기 때문에 임베디드 블록 대신 이것을 좋아합니다 . 나는 또한 여러 임베디드 using블록 이상을 좋아 하지만 ... 내가 선호하는 것입니다.
chezy525

8
많은 예외 처리를 구현하면 실제로 타이핑을 즐기십시오! 그 "사용"키워드는 한동안 사용되어 왔으며 그 의미는 나에게 분명합니다. 그리고 그것을 사용하면 혼란을 최소화하면서 나머지 코드를 더 명확하게 만들 수 있습니다.
Jonathan Wood

2
이것은 올바르지 않습니다. 오브젝트는 try명령문 내에 배치되도록 명령문 외부에서 인스턴스화해야합니다 finally. 그렇지 않으면 컴파일러 오류가 발생합니다 : "할당되지 않은 지역 변수 'myObject'사용"
Steve Konves

3
기술적으로도 컴파일되지 않습니다. Cannot assign null to implicitly-typed local variable;) 그러나 나는 당신이 의미하는 바를 알고 있으며 개인적으로 using 블록을 중첩시키는 것을 선호합니다.
Connell

20

때에 따라 다르지. WCF (Windows Communication Foundation)를 사용하는 using(...) { try... }경우 프록시 입력 using문이 예외 상태 인 경우 (예 :이 프록시를 삭제하면 다른 예외가 발생 함) 제대로 작동하지 않습니다 .

개인적으로, 나는 최소한의 처리 방법, 즉 실행 시점에서 알고있는 예외 만 처리한다고 생각합니다. 즉, 변수 초기화에 using특정 예외 가 발생할 수 있음을 알고 있다면로 감싸 야합니다 try-catch. 마찬가지로, using신체 내부 에서의 변수와 직접 관련이없는 무언가가 발생할 수있는 경우 특정 예외를 위해 using다른 변수로 래핑합니다 try. 나는 Exceptioncatches 에서 거의 사용하지 않습니다 .

그러나 나는 좋아한다 IDisposable그리고 using그렇게하지만 어쩌면 편견.


19

catch 문이 using 문에 선언 된 변수에 액세스해야하는 경우 내부 옵션이 유일한 옵션입니다.

catch 문에서 사용하기 전에 참조 된 객체가 필요하면 내부 옵션이 유일한 옵션입니다.

catch 문이 사용자에게 메시지를 표시하는 것과 같이 알 수없는 기간 동안 작업을 수행하고 그 전에 리소스를 폐기하려면 외부 옵션이 가장 좋습니다.

이와 비슷한 scenerio가있을 때마다 try-catch 블록은 일반적으로 사용보다 콜 스택보다 다른 방법입니다. 메소드가 이와 같이 발생하는 예외를 처리하는 방법을 아는 것은 일반적이지 않습니다.

그래서 나의 일반적인 추천은 바깥에 있습니다.

private void saveButton_Click(object sender, EventArgs args)
{
    try
    {
        SaveFile(myFile); // The using statement will appear somewhere in here.
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}

10

둘 다 유효한 구문입니다. 실제로 원하는 작업을 수행합니다. 개체 생성 / 배치와 관련된 오류를 잡으려면 두 번째를 사용하십시오. 그렇지 않은 경우 첫 번째를 사용하십시오.


8

여기서 중요한 것은 한 가지가 있습니다. 첫 번째 는 생성자 를 호출하여 발생하는 예외를 포착하지 않습니다MyClass .


3

C # 8.0부터는 두 번째 것과 같은 것을 선호합니다

public class Person : IDisposable
{
    public Person()
    {
        int a = 0;
        int b = Id / a;
    }
    public int Id { get; set; }

    public void Dispose()
    {
    }
}

그리고

static void Main(string[] args)
    {

        try
        {
            using var person = new Person();
        }
        catch (Exception ex) when
        (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
        ex.TargetSite.MemberType == System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Constructor Person");
        }
        catch (Exception ex) when
       (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
       ex.TargetSite.MemberType != System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Person");
        }
        catch (Exception ex)
        {
            Debug.Write(ex.Message);
        }
        finally
        {
            Debug.Write("finally");
        }
    }

1

Using () 블록에서 초기화하는 객체가 예외를 throw 할 수 있다면 두 번째 구문을 사용해야합니다. 그렇지 않으면 둘 다 유효합니다.

내 시나리오에서 파일을 열어야하고 Using () 블록에서 초기화하는 객체의 생성자에서 filePath를 전달하고 filePath가 잘못되었거나 비어 있으면 예외가 발생할 수 있습니다. 따라서이 경우 두 번째 구문이 의미가 있습니다.

내 샘플 코드 :-

try
{
    using (var obj= new MyClass("fileName.extension"))
    {

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}

1

에서 의 C # 8.0 , 당신은 간단하게 할 수 using중첩 된 블록을 제거하기 위해 몇 가지 조건에서 문을 한 다음 바로 바깥 쪽 블록에 적용됩니다.

따라서 두 가지 예를 다음과 같이 줄일 수 있습니다.

using var myObject = new MyClass();
try
{
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

과:

try
{
   using var myObject = new MyClass();
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

둘 다 분명하다; 그런 다음 객체 범위의 범위, 인스턴스화 오류를 처리하려는 위치 및 폐기하려는 시점의 문제로 둘 사이의 선택을 줄입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.