views:

143

answers:

6

I have an object that has a disposable object as a member.

public class MyClass
{
    private MyDisposableMember member;

    public DoSomething
    {
         using (member = new MyDisposableMember())
         {
             // Blah...
         }
    }
}

There can be many methods in MyClass, all requiring a using statement. But what if I did this instead?

public class MyClass
{
    private MyDisposableMember member = new MyDisposableMember();

    public DoSomething
    {
         // Do things with member :)
    }

    ~MyClass()
    {
        member.Dispose();
    }
}

As you can see, member is being disposed in the destructor. Would this work? Are there any problems with this approach?

+9  A: 

Ideally, Dispose() should have already been called prior to finalization. It would be better to follow the typical dispose pattern, and allow the user to Dispose() the object properly, and have the finalizer Dispose of it if dispose has not already been called.

In this case, since you're encapsulating an IDisposable, you really don't need to implement the finalizer at all, though. (At the the point of finalization, your encapsulated member will get finalized, so there's no need to finalize your object - it just adds overhead.) For details, read this blog article I wrote on encapsulating an IDisposable.

Reed Copsey
In C# it is actually called a destructor
Rune FS
http://blogs.msdn.com/ericlippert/archive/2010/01/21/what-s-the-difference-between-a-destructor-and-a-finalizer.aspxIt should be called a finalizer.
Ron Warholic
@Rune FS: You are technically correct - the C# language spec. refers to this as a destructor. I'll take that out. However, I personally feel this is a poor choice in terminoloty, since it really is a finalizer, and is turned into a finalizer in GC/CLR terms.
Reed Copsey
@Sid has the right idea, with a very good link as to why...
Reed Copsey
@Reed agreed. Recently read an Eric L. Blog on why they chose that term and one suggested reason was that at the time the finalizer/destructor terms had yet to settle
Rune FS
@Rune FS: It's a shame - calling it a destructor causes confusion, esp. for people with a C++ background. It behaves very, very differently, and may never be called (especially when implementing IDisposable correctly, since you can call GC.Suppress**Finalize**(this); on your object)
Reed Copsey
OK, I read your blog article, but there's still something I don't quite understand. It seems to me like you still need to either call `MyType.Dispose()` explicitly, or wrap it in a `using` statement, neither of which are options for me because `MyType` is being instantiated in a class factory, the code of which I do not control. This is why I'm looking for some sort of self-managed `Dispose()`.
Robert Harvey
@Robert: The point is - You want to allow the user to call Dispose manually. If they DON'T call Dispose manually, the finalizer will already finalize your encapsulated member (since it'll be unrooted at the same time your object is), so there's no reason to add a finalizer to your method.
Reed Copsey
OK. I'll read your three blog articles when I have a little more time. :)
Robert Harvey
+7  A: 

You should probably make MyClass implement IDisposable. Inside the Dispose() method, call member.Dispose();. That way the programmer can have control over when the member gets disposed.

recursive
In this scenario, MyClass can go out of scope without warning. It is being instantiated as part of a factory class, the code of which I don't control.
Robert Harvey
@Robert: There is absolutely no purpose to having a finalizer on your class, provided the encapsulated member was defined correctly. See my answer for details...
Reed Copsey
It will still get disposed eventually by the GC then, but doing it this way just gives the programmer the ability to control it if they want.
recursive
IDisposable is a viral interface... and it is good like this...
BeowulfOF
A: 

The only thing I see wrong (and it isn't an error) is the fact that in a using statement you explicitly dispose of the object at that point in time (when your function / method is called). The destructor cannot be called they are invoked automatically. So at this point it may take some time for member to be disposed of. Better to implement the IDisposeable interface for MyClass.

JonH
+3  A: 

DO NOT DO THAT!

The GC will do that for you (indirectly as the object to dispose or another one will contain a destructor)

MyDisposableMember might even be disposed by the GC even before you dispose it - what happens then might not be what you intended to do.

Even worse: Adding a destructor (or finalizer) to a class costs additional time when disposing of the object (much more time as the object will stay in memory for at least one collection cyclus and maybe even promoted to the next generation).

Therfore, it would be completely useless and even backfire.

winSharp93
So are you saying that if I make MyClass IDisposable, the GC will call Dispose() automatically?
Robert Harvey
The GC doesn't call Dispose if that is what you're saying.
Brian Rasmussen
No: The Dispose of the class you are using exists as the class (directly or indirectly) uses some unmanaged resource. And this resource only has to freed once. If not calling "Dispose" of the object which holds the unmanaged resource explicitly, there will be a finalizer of this object which frees the resource.
winSharp93
By providing an additional "Dipose" method as suggested answers you could give the user of your class the ability to free the unmanaged resource (even if it's used by your class only indirectly) before the object holding it gets disposed. This will improove application performance. In this case, however, your class doesn't need a finalizer (destructor).
winSharp93
A: 

Following the Microsoft pattern is your best bet so the users of your class have full control over when it is disposed.

public class MyClass : IDisposable
{
    private MyDisposableMember member = new MyDisposableMember();

    public DoSomething
    {
         // Do things with member :)
    }

    ~MyClass()
    {
        Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)  // Release managed resources
        {           
            member.Dispose();
        }

        // Release unmanaged resources
    }
}
ChaosPandion
Although this is, technically, the full Dispose pattern for IDisposable, this is intended for when you are encapsulating native resources, not another IDisposable type. There really is no reason to add a finalizer when encapsulating a (properly written) IDisposable. This just adds unneeded overhead. For details, see: http://reedcopsey.com/2009/04/19/idisposable-part-3-encapsulating-an-idisposable-class/
Reed Copsey
A: 

In your first example the member is not really part of the object's state since you're instantiating it every time it's used and disposing it right after. Since it's not part of the state don't model it as such just use a local variable when needed.

In more general you should put all disposal logic in Dispose() and implement IDisposable then use you class together with using or try-finally

Rune FS