1
votes

We all know that IDisposable interface is using for disposing unmanaged resources. I have a class which contains following code. here i have implemented the Dispose method from IDisposable interface.


  class ClassA:IDisposable
    {
    public ClassA()
    {
    Console.WriteLine("ClassBeingTested: Constructor");
    }
    private bool disposed = false;
    Image img = null; 

    public Image Image
    {
    get { return img; }
    } 

    ~ClassA()
    {
    Console.WriteLine("ClassBeingTested: Destructor");
    // call Dispose with false. Since we're in the
    // destructor call, the managed resources will be
    // disposed of anyways.
    Dispose(false); 
    }

    public void Dispose()
    {
    Console.WriteLine("ClassBeingTested: Dispose");
    // dispose of the managed and unmanaged resources
    Dispose(true);

    // tell the GC that the Finalize process no longer needs
    // to be run for this object.
    GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposeManagedResources)
    {
    // process only if mananged and unmanaged resources have
    // not been disposed of.
    if (!this.disposed)
    {
    Console.WriteLine("ClassBeingTested: Resources not disposed");
    if (disposeManagedResources)
    {
    Console.WriteLine("ClassBeingTested: Disposing managed resources");
    // dispose managed resources
    if (img != null)
    {
    img.Dispose();
    img = null;
    }
    }
    // dispose unmanaged resources
    Console.WriteLine("ClassBeingTested: Disposing unmanaged resouces");
    disposed = true;
    }
    else
    {
    Console.WriteLine("ClassBeingTested: Resources already disposed");
    }
    }
    // loading an image
    public void LoadImage(string file)
    {
    Console.WriteLine("ClassBeingTested: LoadImage");
    img = Image.FromFile(file);
    }

    }

What my doubt is why i need to implement the Dispose method from IDisposable interface?. Instead of that i can create my own Dispose method in my class without inheriting from IDisposable interface which i have given below.

for the class below i haven't inherited my class from IDisposable interface. instead of that i created my own dispose method. this also works fine.


    class ClassA
    {
    public ClassA()
    {
    Console.WriteLine("ClassBeingTested: Constructor");
    }
    private bool disposed = false;
    Image img = null;

    public Image Image
    {
    get { return img; }
    } 

    ~ClassA()
    {
    Console.WriteLine("ClassBeingTested: Destructor");
    // call Dispose with false. Since we're in the
    // destructor call, the managed resources will be
    // disposed of anyways.
    Dispose(false); 
    }

    public void Dispose()
    {
    Console.WriteLine("ClassBeingTested: Dispose");
    // dispose of the managed and unmanaged resources
    Dispose(true); 
    // tell the GC that the Finalize process no longer needs
    // to be run for this object.
    GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposeManagedResources)
    {
    // process only if mananged and unmanaged resources have
    // not been disposed of.
    if (!this.disposed)
    {
    Console.WriteLine("ClassBeingTested: Resources not disposed");
    if (disposeManagedResources)
    {
    Console.WriteLine("ClassBeingTested: Disposing managed resources");
    // dispose managed resources
    if (img != null)
    {
    img.Dispose();
    img = null;
    }
    }
    // dispose unmanaged resources
    Console.WriteLine("ClassBeingTested: Disposing unmanaged resouces");
    disposed = true;
    }
    else
    {
    Console.WriteLine("ClassBeingTested: Resources already disposed");
    }
    }
    // loading an image
    public void LoadImage(string file)
    {
    Console.WriteLine("ClassBeingTested: LoadImage");
    img = Image.FromFile(file);
    }
    }

So can any one tel me tat the reason behind of implementing dispose method from IDisposable interface.

6
Your ClassA does not need a destructor (finalizer) and should not have one.Henk Holterman
@Henk - I don't think the question you suggest as a possible duplicate elicited an answer as good as Henrik's answer below, probably because it's not as explicit a question: it seemed to be asking "why dispose?" whereas this question is "why dispose by implementing IDisposable?" to which Henrik gives the answer (i.e. 'using').AAT

6 Answers

6
votes

When you implement IDisposable, you can use using for exception-safe disposing.

2
votes

Two reasons:

  • Implementing IDisposable expresses intent (this should be disposed) in a conventional manner. It's easy to spot that you should dispose of a resource if it implements IDisposable, whereas relying on other developers to read the documentation carefully is more likely to lead to errors.
  • That convention is used by the using statement. You should be able to write:

    using (ClassA foo = new ClassA())
    {
        ...
    }
    

    ... but unless you implement IDisposable, you can't.

(Personally I wouldn't include a finalizer, by the way... that's usually only for directly held unmanaged resources; here you should rely on the Image finalizer.)

2
votes

Although implementing your own dispose method will suffice for any explicit call made to that method but when,after implementig Idispobale, you use a using statement, the built in .Net functionality will invoke your dispose method for you so your code can look like this;

                using (ClassA foo = new ClassA())
                {
                    ...
                }

rather than this

                using (ClassA foo = new ClassA())
                {
                    ....
                    foo.Dispose();
                }
1
votes

When you implement IDisposable interface you can use your class in using block, like this:

...
using(var classA = new ClassA())
{
do some stuff
}

after it your Dispose method will be invoked.

It is quite useful.

1
votes

IDisosable is very useful. For example working with Database connections. It requires all of its implementations to have Dispose method.

It is very useful for working with unmanaged resources, where you have to release them as for the Database connections above, because Garbage Collector is working on managed code (it releases objects where they are not in use anymore), but for unmanaged as C++ application or library (without CLR), it has no idea what is going there. By using its disposable method you say you have finished your work with such a resource and it is being released (freeing memory).

Example (example class and usage):

class Database : IDisposable
{
    private SqlConnection _conn;

    public Database(string conn_str)
    {
        // Doing the connectivity
    }

    public Dataset Read(string sql)
    {
        SqlCommand cmd = new SqlCommand();
        Dataset result = null;
        // etc...
        return result;
    }

    public Dispose()
    {
        _conn.Close();
    }
}

using(Database db = new Database(conn_string))
{
    Dataset ds = db.Read("SELECT something FROM table");
}

The this approach is very useful. In this statement you init your IDisposable and at the end of statement (not needed to call db.Dispose()) its Dispose() is called and the resources are freed. In this case unmanaged resource may be the .NET SQL Driver, you can use MySQL library, etc.

1
votes

Three "unwritten" parts of the contract for .net objects are:

  1. If a class implements IDisposable, then once the instance is no longer needed, calling IDisposable.Dispose() on it and abandoning it should take care of all necessary cleanup, regardless of the type of object.
  2. If an object does not implement IDisposable, it may be safely abandoned any time it is no longer needed, without requiring any cleanup.
  3. An object which constructs an instance of a class which implements IDisposable is responsible for ensuring that IDisposable gets called, either by doing it itself when it is done with the object, or ensuring that the reference gets handed off to some other object which will carry out the responsibility.

This is in general a very useful pattern. While there are some rare occasions when it will be impossible for a class to properly implement IDisposable (most commonly because the class exists to expose a complex resource whose cleanup semantics are understood by the user of the class, but not by the class itself), it's very useful to have a unified means of cleanup when things like exceptions occur.