Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to call Dispose() of IDisposable created in constructor?

Where to call Dispose() for IDisposable objects owned by an object?

public class MyClass
{
    public MyClass()
    {
        log = new EventLog { Source = "MyLogSource", Log = "MyLog" };
        FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
    }


    private readonly EventLog log;
    private readonly FileStream stream;

    // Other members, using the fields above
}

Should I implement Finalize() for this example? What if I do not implement anything at all? Will there be any problems?

My first thought was that MyClass should implement IDisposable. But the following statement in an MSDN article confused me:

Implement IDisposable only if you are using unmanaged resources directly. If your app simply uses an object that implements IDisposable, don't provide an IDisposable implementation.

Is this statement wrong?

like image 940
Andrej Adamenko Avatar asked Sep 29 '14 10:09

Andrej Adamenko


People also ask

When Dispose is called in IDisposable?

Rule#1: Properly dispose of classes that implement IDisposable. The first rule is whenever you are consuming a class that implements the IDisposable interface; you should call the “Dispose” method when you are done with that class.

How do I call a Dispose method?

public void Dispose() { Dispose(disposing: true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC. SuppressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time.

What will happen if we call Dispose () method directly?

The Dispose() methodThe Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object. Finalize override. Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. If the type has no finalizer, the call to GC.

Is Dispose automatically called C#?

Dispose() will not be called automatically. If there is a finalizer it will be called automatically. Implementing IDisposable provides a way for users of your class to release resources early, instead of waiting for the garbage collector.


2 Answers

If MyClass owns an IDisposable resource, then MyClass should itself be IDisposable, and it should dispose the encapsulated resource when Dispose() is called on MyClass:

public class MyClass : IDisposable {
    // ...
    public virtual void Dispose() {
        if(stream != null) {
            stream.Dispose();
            stream = null;
        }
        if(log != null) {
            log.Dispose();
            log = null;
        }
    }
}

No, you should not implement a finalizer here.

Note: an alternative implemention might be something like:

private static void Dispose<T>(ref T obj) where T : class, IDisposable {
    if(obj != null) {
        try { obj.Dispose(); } catch {}
        obj = null;
    }
}

public virtual void Dispose() {
    Dispose(ref stream);
    Dispose(ref log);
}
like image 189
Marc Gravell Avatar answered Oct 07 '22 14:10

Marc Gravell


For objects containing other IDisposable objects, it's a good and recommended practice to implement IDisposable on your own object, so others consuming your type can wrap it in a using statement:

public class MyClass : IDisposable
{
    public MyClass()
    {
        log = new EventLog { Source = "MyLogSource", Log="MyLog" };
        FileStream stream = File.Open("MyFile.txt", FileMode.OpenOrCreate);
    }


    private readonly EventLog log;
    private readonly FileStream stream;

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Free managed objects here
            stream.Dispose();
        }
    }

    // Other members, using the fields above
}

In your case, you aren't freeing up any managed resources so no finalizer is needed. If you were, then you would implement a finalizer and call Dispose(false), indicating to your dispose method that it is running from the finalizer thread.

If you don't implement IDisposable, you're leaving it up to the GC to clean up the resources (e.g, close the Handle on the FileStream you've opened) once it kicks in for collection. Lets say your MyClass object is eligible for collection and is currently in generation 1. You would be leaving your FileStream handle open until the GC cleans up the resource once it runs. Also, many implementations of Dispose call GC.SuppressFinalize to avoid having your object live another GC cycle, passing from the Initialization Queue to the F-Reachable queue.

like image 24
Yuval Itzchakov Avatar answered Oct 07 '22 16:10

Yuval Itzchakov