2010-03-22 2 views
21

IDisposable을 구현해야하는 부모 및 자식 클래스가 있습니다. virtual (및 base.Dispose()?) 전화는 어디에서 작동해야합니까? 그냥 Dispose(bool disposing) 호출을 덮어 씌우면 실제로 Dispose() 함수 (그냥 상속 된 것을 사용함)를 갖지 않고 IDisposable을 구현한다는 사실이 이상하다고 느끼지만 그 밖의 모든 것은 가지고 있습니다.부모가 IDisposable을 구현할 때 하위 클래스에 IDisposable 구현

내가 (평범 꽤)하고 있었다 무엇

:

internal class FooBase : IDisposable 
{ 
    Socket baseSocket; 

    private void SendNormalShutdown() { } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private bool _disposed = false; 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       SendNormalShutdown(); 
      } 
      baseSocket.Close(); 
     } 
    } 

    ~FooBase() 
    { 
     Dispose(false); 
    } 
} 

internal class Foo : FooBase, IDisposable 
{ 
    Socket extraSocket; 

    private bool _disposed = false; 
    protected override void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      extraSocket.Close(); 
     } 
     base.Dispose(disposing); 
    } 

    ~Foo() 
    { 
     Dispose(false); 
    } 

} 
+0

[MSDN (https://msdn.microsoft.com/en-us/library/system.idisposable (V = vs.110)는 .aspx0)는 IDisposable 구현 객체를 서브하는 방법에 대한 추천을 갖는다 . – PeterM

답변

23

난 그냥 폐기 (BOOL이 폐기) 호출을 무시할 때, 명시 적으로 폐기하지 않고 내가으로 IDisposable 구현한다는 정말 이상한 느낌() 함수 (단지 상속 된 것을 이용함).

이것은 사용자가 신경 쓰지 말아야 할 사항입니다.

IDisposable 클래스를 하위 클래스로 만들면 모든 "Dispose pattern"배관이 기본 클래스에 의해 이미 처리되고 있습니다. 실제로는 아무 것도하지 말고 protected Dispose(bool) 메서드를 무시하고 이미 처분했는지 여부를 추적하십시오 (ObjectDisposedException을 올바르게 올리십시오).

자세한 내용은 내 블로그 게시물 Subclassing from an IDisposable class을 참조하십시오.


또한, 자주, 그것은으로 IDisposable 클래스를 캡슐화하는 대신 그것을 서브 클래스 고려하는 것이 좋습니다. IDisposable 클래스를 서브 클래 싱하는 것이 적절할 때도 있지만, 드물다. 종종 캡슐화가 더 나은 대안입니다.

+0

아, 내 걱정은 근거가없는 것 같아요. 나는 그 일을 제대로 수행하기에 가까웠습니다. (어디에서 파이널 라이저를 다시 구현할 것인지 생각해 냈습니다.) 그리고 일반적으로 상속은 내가 ​​점점 더 적게 사용하는 것을 발견합니다. – Tanzelax

+0

Reed your blog is brilliant ...하지만 대답의 수를 기록해 둡니다 - 7 (1은 광산입니다 :)) .... 사람들은 충분히 부끄럽지 않습니다. –

3

이 패턴의 아이디어는 당신이 필요한 경우 base.Dispose를 호출, 가상 Dispose 메소드를 오버라이드 (override)이다. 기본 클래스는 나머지를 처리하여 가상 Dispose 메서드 (따라서 올바른 구현)를 호출합니다. 서브 클래스는 IDisposable을 구현할 필요가 없습니다 (이 상속을 통해 IDisposable입니다)

+1

나는 그 인터페이스를 이미 상속 받았기 때문에 명시 적으로': IDisposable'을 꺼낼 수 있다고 가정합니다. 나는 "이 수업에는 특별한 처분이 있습니다"라고 명시 적으로 언급하고 싶습니다. 그래도 의견을 보내 주셔서 감사합니다. :) – Tanzelax

1

하위 클래스는 가상 Dispose를 무시하고 하위 클래스에 특정한 처리를 수행하고 수퍼 클래스 Dispose를 호출하여 차례대로 자체 작업을 수행해야합니다.

편집 : http://davybrion.com/blog/2008/06/disposing-of-the-idisposable-implementation/은 내가 이와 같은 경우에 따르는 패턴입니다. '일회용'클래스가 아니라 상속 및 우선 적용.

+0

이미 부풀린 IDisposable 패턴에 더 많은 가상/추상 메서드를 추가하는 아이디어가 마음에 들지는 모르겠습니다 ... – Tanzelax

+0

@Tanzelax 각자 자신에게로, 나는 생각합니다. 제공되는 코드는 일회용 클래스 일 필요가있는 곳에서 유용합니다. 대부분의 설정은 최상위 클래스에 있으며 하위 클래스 당 최소한의 추가 코드가 필요합니다. –

3

왜 필요하지 않을 때 상황이 복잡합니까?

관리되지 않는 리소스를 캡슐화하지 않으므로 완성과 관련하여 모든 것을 망칠 필요는 없습니다. 그리고 클래스는 내부 클래스이므로 자신의 어셈블리 내에서 상속 계층 구조를 제어 할 것을 제안합니다.

그래서, straighforward 방법은 다음과 같습니다 심지어

internal class FooBase : IDisposable 
{ 
    Socket baseSocket; 

    private void SendNormalShutdown() 
    { 
    // ... 
    } 

    private bool _disposed = false; 

    public virtual void Dispose() 
    { 
    if (!_disposed) 
    { 
     SendNormalShutdown(); 
     baseSocket.Close(); 
     _disposed = true; 
    } 
    } 
} 

internal class Foo : FooBase 
{ 
    Socket extraSocket; 

    private bool _disposed = false; 

    public override void Dispose() 
    { 
    if (!_disposed) 
    { 
     extraSocket.Close(); 
     _disposed = true; 
    } 

    base.Dispose(); 
    } 
} 

당신이 관리되지 않는 리소스를 수행 할 때, 당신이 자신의 일회용 클래스 encapsulating them 오프 훨씬 더 좋을 것 같아라고 말하고 싶지만 당신이 좋겠를 사용하여 다른 일회용품을 사용하십시오. 위 코드와 똑같습니다.

+1

부모 클래스가 아닌 경우 하위 클래스에서 정리 마무리자를 사용해야하는 경우를 생각해 볼 수 있습니까? (Object에서 상속하는 간단한 경우는 제외하고)? 부적절하게 버려진 객체에 불만을 토로하는 마무리자를 추가하는 것을 이해할 수 있지만 정리가 필요한 IMHO는 자체 완성 가능 클래스에 있어야합니다. 나는 * NO * 예외를 생각할 수있다. – supercat

+0

@supercat : 전적으로 동의합니다 (http://codecrafter.blogspot.com/2010/01/revisiting-idisposable.html). –

0

나는 항상이 패턴에 대한 Joe Duffy의 매우 심오한 연구를 참조하십시오. 저를 위해, 그의 버전은 복음입니다.

http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/

기억해야 할 첫 번째 일은 파이널 라이저는 대부분의 시간을 필요로하지 않는 것입니다. 네이티브 리소스를 직접 보유하고있는 관리되지 않는 리소스, 즉 자체 파이널 라이저가없는 리소스 만 정리하는 데 사용됩니다.

다음은 기본 클래스 하위 클래스 쌍의 예입니다.

// Base class 

    #region IDisposable Members 

    private bool _isDisposed; 

    public void Dispose() 
    { 
     this.Dispose(true); 
     // GC.SuppressFinalize(this); // Call after Dispose; only use if there is a finalizer. 
    } 

    protected virtual void Dispose(bool isDisposing) 
    { 
     if (!_isDisposed) 
     { 
      if (isDisposing) 
      { 
       // Clear down managed resources. 

       if (this.Database != null) 
        this.Database.Dispose(); 
      } 

      _isDisposed = true; 
     } 
    } 

    #endregion 


// Subclass 

    #region IDisposable Members 

    private bool _isDisposed; 

    protected override void Dispose(bool isDisposing) 
    { 
     if (!_isDisposed) 
     { 
      if (isDisposing) 
      { 
       // Clear down managed resources. 

       if (this.Resource != null) 
        this.Resource.Dispose(); 
      } 

      _isDisposed = true; 
     } 

     base.Dispose(isDisposing); 
    } 

    #endregion 

하위 클래스에는 _isDisposed 멤버가 있습니다. 또한 이러한 블록에서 예외를 원하지 않기 때문에 리소스에 대해 null 확인을하십시오.

루크

관련 문제