2

Microsoft design guidelines mention Dispose pattern and scenarios how to use it:

DO implement the Basic Dispose Pattern on types containing instances of disposable types. See the Basic Dispose Pattern section for details on the basic pattern.

Later, they show the Basic Dispose Pattern as follows:

public class DisposableResourceHolder : IDisposable {  

    private SafeHandle resource; // handle to a resource  

    public DisposableResourceHolder(){  
        this.resource = ... // allocates the resource  
    }  

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

    protected virtual void Dispose(bool disposing){  
        if (disposing){  
            if (resource!= null) resource.Dispose();  
        }  
    }  
} 

My questions are:

  1. Why do we need to implement Dispose(bool) if it has just a single call with parameter true? It could be easily simplified to just parameterless Dispose() {resource?.Dispose();}. Note we don't need finalizer here because objects we are referencing are managed and have their own finalizers, so they won't be leaked.
  2. Why do they recommend to call GC.SuppressFinalize(this) while not having finalizer? GC anyway wouldn't call finalizer because it does not exist!
  3. The only case when I see the need of Dispose(bool) is when we really have some unmanaged references, which does not implement IDisposable nor finalizer (like shown in this article). But then the meaning of bool disposing would be bool includingManagedResources. So why is it named so misleading 'disposing' to what it should do in fact?
Sasha
  • 8,537
  • 4
  • 49
  • 76
  • 1
    You don't. Microsoft worried about these things because they wrote classes that have finalizers. Never write your own finalizer. It just took a while for Microsoft to discover that as well, then they created the SafeHandle classes. – Hans Passant Oct 11 '17 at 15:31
  • 1
    The reasoning behind this pattern is one can inherit from your class and that inherited class might have finalizer. And no - you don't need to do this. – Evk Oct 11 '17 at 15:39
  • @Evk that actually makes sense... Thank you! – Sasha Oct 11 '17 at 20:08

1 Answers1

1
  1. Other classes could inherit from your class. Considering that the deriving class also holds unmanaged resources (recommended or not), this class should then add the finalizer calling Dispose(false). If your class was sealed I would agree with you.

  2. Because the method void Dispose() should not be virtual following the guidelines from Microsoft and thus deriving classes would then have no chance to suppress finalization after disposal. Your implementation might not need a finalizer, but probably deriving classes do.

  3. It's called disposing for no specific reason in my opinion. I personally would rename it as well.

Anyway, from my point of view it is not a good approach to mix owning managed and unmanaged resources. As already mentioned in the comment even Microsoft recommends to encapsulate unmanaged resources into managed ones thus the cases where you need to implement finalizers are probably rare. I cannot remember when I did this myself the last time.

I am also not sticking to the implementation from the guidelines for multiple reasons, like misleading naming or because it's hard to understand. An alternative approach would be this answer.

Peit
  • 882
  • 6
  • 17
  • Item 2 need [citation required]. The only thing I can find it that it should not be virtual only if the class implements the Disposable pattern. – Hans Passant Oct 11 '17 at 15:53
  • @HansPassant The originally linked document already states "DO NOT make the parameterless Dispose method virtual.". Edit: I think I now understand your comment. It is of course not prohibited to write a virtual dispose method. It's just not the recommended way in terms of the referenced document. The alternative approach I added, which does not stick to this guidelines, does it differently. – Peit Oct 11 '17 at 15:56
  • Right, it is only sensible advice for the disposable pattern, Dispose(bool) is already virtual. It is just fine when you don't use the pattern. And recommended unless you declare the class sealed. – Hans Passant Oct 11 '17 at 16:05