처분 또는 파괴자에서 가상 방법을 호출해도 괜찮습니까?

StackOverflow https://stackoverflow.com/questions/137621

  •  02-07-2019
  •  | 
  •  

문제

나는 그것에 대한 언급을 찾을 수 없지만, 파괴자 또는 disispose () 메소드 내에서 가상 (다형성) 방법을 호출하는 것이 좋지 않다는 것을 읽은 것을 기억합니다.

이것이 사실입니까? 그렇다면 누군가가 이유를 설명 할 수 있습니까?

도움이 되었습니까?

해결책

Finalizer/에서 가상 메소드 호출/Dispose 같은 이유로 안전하지 않습니다 생성자에서 수행하는 것은 안전하지 않습니다. 파생 클래스가 가상 방법이 제대로 실행 해야하는 일부 상태를 아직 정리하지 않았는지 확인하는 것은 불가능합니다.

어떤 사람들은 표준 일회용 패턴과 가상 방법의 사용에 의해 혼란스러워합니다. virtual Dispose(bool disposing), 그리고 이것이 사용해도 괜찮다고 생각하십시오 어느 가상 메소드는 처분 할 수 있습니다. 다음 코드를 고려하십시오.

class C : IDisposable {
    private IDisposable.Dispose() {
        this.Dispose(true);
    }
    protected virtual Dispose(bool disposing) {
        this.DoSomething();
    }

    protected virtual void DoSomething() {  }
}
class D : C {
    IDisposable X;

    protected override Dispose(bool disposing) {
        X.Dispose();
        base.Dispose(disposing);
    }

    protected override void DoSomething() {
        X.Whatever();
    }
}

다음은 처분 할 때 발생하는 일과 유형의 대상입니다. D, 라고 불리는 d:

  1. 일부 코드 호출 ((IDisposable)d).Dispose()
  2. C.IDisposable.Dispose() 가상 메소드를 호출합니다 D.Dispose(bool)
  3. D.Dispose(bool) 처분 D.X
  4. D.Dispose(bool) 전화 C.Dispose(bool) 정적으로 (통화 대상이 알려져 있습니다 컴파일 타임에)
  5. C.Dispose(bool) 가상 방법을 호출합니다 D.DoSomething()
  6. D.DoSomething 메소드를 호출합니다 D.X.Whatever() 이미 폐기 된 D.X
  7. ?

이제이 코드를 실행하는 대부분의 사람들은이 코드를 고치기 위해 한 가지를 수행합니다. base.Dispose(dispose) 그들이 자신의 물건을 정리하기 전에 전화하십시오. 그리고 그렇습니다. 그것은 효과가 있습니다. 그러나 당신은 당신이 개발 한 회사의 Ultra-Junior 개발자 인 프로그래머 X를 정말로 신뢰합니까? C 글을 쓰기 위해 할당되었습니다 D, 오류가 감지되거나 base.Dispose(disposing) 올바른 지점에서 전화 하시겠습니까?

나는 당신이 절대 절대로 말하지 말아야한다고 말하는 것이 아닙니다. 항상 dispose에서 가상 메소드를 호출하는 코드를 작성합니다. 문서 그 가상 방법 요구 사항 아래에서 파생 된 클래스에서 정의 된 상태를 사용하지 않는다는 C.

다른 팁

가상 방법은 생성자와 소멸자 모두에서 권장하지 않습니다.

그 이유는 무엇보다도 더 실용적입니다. 가상 방법은 오버라이더가 선택한 방식으로 상체 될 수 있으며, 예를 들어, 구조 중 객체 초기화와 같은 것들이 있습니다. 보장해야합니다 무작위 널과 무효 상태가있는 물체로 끝나지 않도록하십시오.

가상 방법을 호출하는 것에 대한 권장 사항이 있다고 생각하지 않습니다. 당신이 기억하고있는 금지는 결승전에서 관리 된 객체를 참조하는 것에 대한 규칙 일 수 있습니다.

dispose ()를 구현하는 방법에 대한 .NET 문서로 정의되는 표준 패턴이 있습니다. 패턴은 매우 잘 설계되었으며 밀접하게 따라야합니다.

요점은 이것입니다 : dispose ()는 가상 메소드 dispose (bool)를 호출하는 비가적인 방법입니다. 부울 매개 변수는 메소드가 dispose () (true)에서 호출되는지 또는 객체의 파괴자 (false)에서 호출되는지 여부를 나타냅니다. 각 상속 레벨에서 Dispose (BOOL) 방법을 구현하여 정리를 처리해야합니다.

Dispose (BOOL)가 값이 합당되면 Finalizer가 Dispose Method를 호출했음을 나타냅니다. 이 상황에서는 관리되지 않는 물체의 정리 만 시도해야합니다 (특정 드문 상황 제외). 그 이유는 쓰레기 수집기가 방금 최종 방법이라고 불렀기 때문에 현재 객체는 기성품으로 표시되어 있어야합니다. 따라서, IT 참조의 임의의 대상은 또한 자극적 인 판독으로 표시되었을 수 있으며, 비 결정적으로 서열이 발생하기 때문에 완료가 이미 발생했을 수 있습니다.

.NET 문서에서 Dispose () 패턴을 찾아보고 정확하게 따라가는 것이 좋습니다. 기괴하고 어려운 버그로부터 당신을 보호 할 수 있기 때문입니다!

Jon의 답변을 확장하려면 가상 메소드를 호출하는 대신 해당 레벨에서 리소스를 처리 해야하는 경우 서브 클래스에서 처분 또는 파괴자를 무시해야합니다.

비록 여기서 행동과 관련하여 "규칙"이 있다고 생각하지 않습니다. 그러나 일반적인 생각은 자원 정리를 해당 구현 수준에서 해당 인스턴스로만 분리하고 싶다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top