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?
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.
If you don't use using , then it's up to you (the calling code) to dispose of your object by explicitely calling Dispose().
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.
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.
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.
"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:
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.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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With