2010-04-20 2 views
2

특정 상황에서 다음과 비슷한 클래스의 모든 예외를 처리하려면 어떻게해야합니까? ctor와 finalizer가 예외를 throw하는 C# 클래스의 모든 예외를 처리하려면 어떻게해야합니까?

class Test : IDisposable { 
    public Test() { 
    throw new Exception("Exception in ctor"); 
    } 
    public void Dispose() { 
    throw new Exception("Exception in Dispose()"); 
    } 
    ~Test() { 
    this.Dispose(); 
    } 
} 

내가 이것을 시도했지만 작동하지 않습니다 나는 또한 "사용"를 사용하는 것을 시도했다

static void Main() { 
    Test t = null; 
    try { 
    t = new Test(); 
    } 
    catch (Exception ex) { 
    Console.Error.WriteLine(ex.Message); 
    } 

    // t is still null 
} 

을하지만 ~ 시험에서 던진 예외를 처리하지 않습니다();

static void Main() { 
    try { 
    using (Test t = new Test()) { } 
    } 
    catch (Exception ex) { 
    Console.Error.WriteLine(ex.Message); 
    } 
} 

어떻게 해결할 수 있습니까?

+0

두 번째 경우 (사용하지 않음)에는 실제로 Dispose()를 호출하지 않습니다. C#은 가비지 수집되므로 GC가 정리할 시간을 결정할 때까지 클래스는 실제로 정리되지 않습니다.또한 GC는 Dispose를 호출하지 않으므로 (정의하더라도) '사용'을 사용하거나 IDisposable 클래스를 사용할 때 Dispose를 명시 적으로 호출해야합니다. –

+0

답변 해 주셔서 감사합니다. 사실, Test 클래스는 저에게 쓰여진 것이 아니며, 단지 컨트롤 목적 밖에있는 비슷한 동작을 가진 클래스를 보여주는 데모 용입니다. 요점은 예외를 던지는 생성자는 Test 객체가 참조 변수가없는 반제품이라는 점입니다. – Frank

답변

5

먼저 완료 자는 이 아니며은 예외를 throw해야합니다. 그럴 경우, 무언가가 치명적으로 잘못되어 앱이 크게 충돌합니다. 또한 Finalizer는 절대로 Dispose()를 직접 호출하면 안됩니다. Finalizer는 관리되지 않는 리소스를 릴리스 할 때만 사용됩니다. Finalizer가 실행되면 관리되는 리소스가 유효한 상태가 아닐 수도 있습니다. 관리되는 참조는 이미 가비지 수집기에서 정리되므로 Finalizer가 아닌 Dispose에서만 삭제해야합니다.

그렇다면 Dispose를 명시 적으로 호출하면 Dispose의 Exception을 발견해야합니다. 나는 'using'케이스가 예외를 던지지 않은 방법을 잘 이해하지 못했다. 그렇다면 Dispose는 예외를 피할 수 있으면 예외를 던져서는 안됩니다. 특히, 사용 블록 이후에 예외를 발생시키는 Dispose는 사용 블록 내에서 Dispose 예외로 발생할 수있는 모든 예외를 '덮어 씁니다'.


일부 추가 참조 자료는 here

+0

문제는 생성자가 예외를 throw하면 "부분"개체에 대한 포인터가 없어서 Dispose()를 명시 적으로 호출 할 수 없다는 것입니다. 또한 "using"문을 사용하면 생성자의 예외가 catch되지만 GC가 finalizer를 호출하면 처리 할 수없는 또 다른 예외가 있습니다. – Frank

+0

부분적으로 관리되지 않는 리소스가 할당 된 후 개체가 생성자에서 예외를 throw하면 개체의 디자인 결함입니다. 불행히도 그것에 대해 할 수있는 일은 없습니다. 객체가 구축 중에 예외를 던져야한다면 가능한 경우 관리되지 않는 할당을 '롤백'하는 것이 좋습니다. 더 나은 점은 생성자에서 실패 할 수있는 로직을 다른 Init 메소드로 옮기는 것입니다. –

3

나는 대답의 일부는 당신이이 경우에 예외를 처리하지 않아야 생각합니다.

예외를 복구 할 수 있거나 예외에 정보를 추가하고 다시 게시 할 수있는 경우에만 예외를 catch해야합니다. 모든 예외를 포착해서는 안됩니다. 호출 스택에서 코드를 가능한 한 많은 예외없이 처리하도록하십시오.

1

나는 몇 가지 관찰을하고있다.

먼저 Dispose에서 예외를 throw하지 마십시오. 사실, 나는 결코 거의 말하지 않을 것입니다. .NET 개발자는 Dispose가 항상 성공하고 좋은 이유가 있음을 기대합니다. 매번 try-catch를 호출하는 것은 어색한 일이며, 가독성이 떨어질 수 있습니다.

둘째, 자주 논의되는 문제이므로 생성자에서 예외가 발생하지 않도록하십시오. ArgumentException 또는 IndexOutOfRangeException과 같은 상태의 유효성 확인과 관련된 예외는 일반적으로 사전 조건 위반으로 인해 생성되며 일반적으로 프로그래밍 오류로 인해 발생합니다. 그러나 SqlException과 같은 예측할 수없는 예외는 호출자가 try-catch 블록에서 생성자를 래핑하도록 할 것입니다. 다시 말하지만, 이것은 어색한 코딩 시나리오를 초래합니다. 그러나 더 중요한 것은 생성자가 관리되지 않는 리소스를 할당 한 다음 새 인스턴스를 호출자에게 반환하기 전에 예외를 throw하는 시나리오에서 미묘한 리소스 누수가 발생할 수 있다는 것입니다. 인스턴스 참조가 없으면 호출자는 Dispose를 호출 할 수 없습니다.

관련 문제