Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to dispose an object of which I only have an interface? [duplicate]

How can I determine if I should extend one of my interfaces with IDisposable or implement IDisposable on a class that implements my interface?

I have an interface that does not need to dispose of any external resources, except for one particular implementation. My options seem to be:

1) Implement IDisposable on the interface requiring all of the implementations to implement Dispose, even if only an empty method.

-or-

2) Implement IDisposable on only the classes that have resources needing to be disposed. This will cause problems with "using" because my object is created from a factory and therefore all upstream code works against the interface. Since the interface is not bound to IDisposable, "using" does not see the Dispose method. However, I could cast the factory result to the implementation; however, that then makes the consumer aware of the implementation, defeating the purpose of interfaces.

Any ideas as to best practices?

like image 838
Peter Rilling Avatar asked Jan 16 '13 22:01

Peter Rilling


People also ask

What is the interface of Dispose method?

IDisposable is an interface that contains a single method, Dispose(), for releasing unmanaged resources, like files, streams, database connections and so on.

What is the interface from which the Dispose () method inherited?

Dispose is inherited by its derived classes. Instead, to clean up a derived class, you provide the following: A protected override void Dispose(bool) method that overrides the base class method and performs the actual cleanup of the derived class. This method must also call the base.

Which interface allows implement the Dispose method to do cleanup work?

Typically, types that use unmanaged resources implement the IDisposable or IAsyncDisposable interface to allow the unmanaged resources to be reclaimed. When you finish using an object that implements IDisposable, you call the object's Dispose or DisposeAsync implementation to explicitly perform cleanup.

What does Dispose method to with connection object?

Deletes it from the memory.


3 Answers

If you expect callers to only be able to interact with the interface, and never the implementation, then you want to have the interface extend IDisposable. If not, they'll need to check if the value is IDisposable anyway to see if it needs to be disposed.

If the object responsible for disposing of the object knows of the concrete implementation, and it is only ever objects that are given references to it (but aren't responsible for disposing of it) that use the interface, then consider the second option.

A good example of the first option is IEnumerator. Many IEnumerator objects don't need to do anything when they're disposed, but some do, and so the interface extends IDisposable because the object responsible for the creation/lifecycle of that object will (or should) never have knowledge of the underlying implementation.

An example of the second would be something like IComparer many objects that need to be compared are disposable, but the sections of code using an object through the interface aren't responsible for it's creation/lifecycle, so it needs no knowledge of whether or not that type is disposable.

like image 88
Servy Avatar answered Oct 20 '22 18:10

Servy


The $50,000 question is whether responsibility of disposal will ever be passed along with the interface or, to put it another way, whether the last entity to use an implementing object might be something other than the entity which creates it.

The big reason that IEnumerator<T> implements IDisposable is that implementing objects are created by objects that implement IEnumerable<T>.GetEnumerator() but are then generally used by other objects. The object that implements IEnumerable<T> will know whether the thing it returns really needs disposing, but will have no way of knowing when the recipient is done with it. The code that calls IEnumerable<T>.GetEnumerator() will know when it's done with the returned object, but will have no way of knowing whether it needs any cleanup. The sensible thing to do is specify that the code which calls IEnumerable<T>.GetEnumerator() is required to ensure that the returned object will have Dispose called on it before it is abandoned; the Dispose method will in many cases not do anything, but unconditionally calling a do-nothing method which is guaranteed to exist is cheaper than checking for the existence of a method that does not exist.

If the nature of your interface type is such that the the questions of whether an implementing object needs cleanup and when such cleanup should occur will both be answerable by the same entity, then there's no need for the interface to inherit IDisposable. If instances will be created by one entity but last used by another, then inheriting IDisposable would be wise.

like image 27
supercat Avatar answered Oct 20 '22 18:10

supercat


If you implement IDisposable on the concrete class and the interface users know that it might be Disposable; you can do

IFoo foo = Factory.Create("type");
using(foo as IDisposable){
    foo.bar();
}

If foo does not implement IDisposable, the using will amount to using(null) which will work just fine.

The output of the below sample program will be

Fizz.Bar
Fizz.Dispose
Buzz.Bar

Sample program

using System;

internal interface IFoo
{
    void Bar();
}
internal class Fizz : IFoo, IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("Fizz.Dispose");
    }

    public void Bar()
    {
        Console.WriteLine("Fizz.Bar");
    }
}
internal class Buzz : IFoo
{
    public void Bar()
    {
        Console.WriteLine("Buzz.Bar");
    }
}

internal static class Factory
{
    public static IFoo Create(string type)
    {
        switch (type)
        {
            case "fizz":
                return new Fizz();
            case "buzz":
                return new Buzz();
        }
        return null;
    }
}

public class Program
{

    public static void Main(string[] args)
    {

        IFoo fizz = Factory.Create("fizz");
        IFoo buzz = Factory.Create("buzz");

        using (fizz as IDisposable)
        {
            fizz.Bar();
        }
        using (buzz as IDisposable)
        {
            buzz.Bar();
        }
        Console.ReadLine();
    }

}
like image 34
QuinnG Avatar answered Oct 20 '22 17:10

QuinnG