Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should factory keep track of created IDisposable objects?

Consider the following simple factory example:

public class MyFactory : IMyFactory
{
    public MyObject CreateObject()
    {
        return new MyObject();
    }
}

In this example, MyObject implements the IDisposable interface. Typically I would expect the consuming program to use this as follows:

// Use using to properly dispose of MyObject
using (MyObject obj = myFactory.CreateObject())
{
    // ...
}

Is it common practice to expect the developer consuming the Factory to handle disposal like this? Or should the Factory keep a list of objects it has created and make sure they are cleaned up periodically, or, possibly when the factory is disposed?

like image 761
Sam Avatar asked Dec 18 '14 06:12

Sam


People also ask

What happens if you dont Dispose IDisposable?

IDisposable is usually used when a class has some expensive or unmanaged resources allocated which need to be released after their usage. Not disposing an object can lead to memory leaks.

How do you Dispose of IDisposable?

If you don't use using , then it's up to you (the calling code) to dispose of your object by explicitely calling Dispose().

What does it mean when an object implements IDisposable?

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.

Why should we implement IDisposable?

in a class, you should implement IDisposable and overwrite the Dispose method to allow you to control when the memory is freed. If not, this responsibility is left to the garbage collector to free the memory when the object containing the unmanaged resources is finalized.


2 Answers

A type implementing IDisposable provides a way for the consumer of the type to deterministically clean up any unmanaged resources used by the type. E.g., when a FileStream is disposed the underlying OS file handle is closed.

Any properly implemented type that directly uses an unmanaged resource (e.g file handle, database connection, native socket etc.) will also have a finalizer to release the unmanaged resource when the object is garbage collected. It is up to the consumer of the type to either use IDisposable to deterministically release the unmanaged resource or simply wait for the garbage collector to do it. In most cases you want to go the deterministic route. E.g., you do not want to wait for the garbage collector before a file becomes accessible from other processes. You want to close the file as soon as you are done working with that file.

So the garbage collector in combination with finalizers will perform the task that you try to delegate to your factory and because your factory is not the garbage collector you will probably have a very hard time to actually implement this "tracking and automatic clean up".

So my primary answer to your question is, no, the factory should not keep track of created IDisposable objects.

However, if your factory is some sort of container that controls the lifetime of the created objects you can make the factory itself IDisposable and then dispose all created objects on disposal. This is a common pattern in dependency injection containers that are used in response-request cycles like in web applications. The container is created at the start of the request and disposed when the response is complete. The consumers of the types created by the factory are oblivious to the fact the some of the types have to be disposed when the request ends.

like image 80
Martin Liversage Avatar answered Sep 18 '22 21:09

Martin Liversage


"It depends"

When a factory creates IDisposable objects, it often makes sense for the client to dispose of them.

But a common factory pattern is to produce objects which are built using other disposables, but are not themselves disposable. Why would you do that? Because of the viral nature of IDisposable:

If you have a type that is composed out of 5 other inner types, and only the "inner most" is an IDisposable you have a choice:

  • you can implement the IDisposable pattern on all 5 types so that when you dispose of the "outer most" instance, the one genuine disposable get disposed correctly. This obviously requires a fair bit of cruft and affects the design of every type in your composition.
  • or, you can inject the one genuine disposable into your object composition from the factory, and let the factory manage the lifetime of the disposable. In this way the factory starts to fill more of a lifetime management role.

You do see examples of both approach in the real world, but I personally do not like implementing IDisposable just for viral reasons (i.e. my type is creating an IDisposable so must be IDisposable itself - as per .NET Framework Design Guidelines).

WCF's ChannelFactory keeps a list of all the channels it has created and closes them when you Dispose the factory. Similarly many IoC containers (which are themselves essentially super-factories) support a lifetime management role via things like StructureMap's GetNestedContainer() or Autofac's BeginLifetimeScope()

like image 32
Jack Ukleja Avatar answered Sep 17 '22 21:09

Jack Ukleja