Reputation: 10113
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?
Upvotes: 8
Views: 2894
Reputation: 13521
"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()
Upvotes: 1
Reputation: 81197
If a factory does not trust that code using the objects it creates will reliably call Dispose
upon them, it may be necessary to have the factory keep a link of weak references to such objects along with the information necessary to clean them up. That's an ugly pattern, but in some cases it may be better than any workable alternative if it's important to ensure that abandoned objects get cleaned up. While there are times when it's better to have the produced objects clean themselves up using destructors or Finalize
, there are others when it's better to have the factory in charge of such cleanup. For example, if a factory's products subscribe to logical events from the factory, normal event subscriptions would keep those objects from ever getting finalized during the lifetime of the factory. If instead the factory keeps a list of WeakReference
to such objects, each notification can cause all live objects to have their notification method invoked, and all dead objects to have their WeakReference
removed from the list.
Upvotes: 0
Reputation: 106876
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.
Upvotes: 15
Reputation:
Absolutely NOT. Even in real world example, No real factory keep track of its products being trashed after their useful life.
Interesting, I was not assuming some technical discussions to a very simple question. In order to understand we have understand the analogy of the terms:
FACTORY: A term used to point to the object that is responsible for creating instances of types it can handle.
LIFE TIME MANAGER: A term used to point to the object that is responsible for the life time of the created instances. It usually work with more than one related instances, such as in the case of Dependency Resolver where it can dispose the dependency object as soon as the dependent object goes out of the scope.
Therefore, it would be better not to tie up so many things within a single class unnecessarily. I would appreciate the experts opinion on this.
Upvotes: 0
Reputation: 5684
When you implement IDisposable
you have to implement yourself the cleaning method for every class. In other words GC
won't clean it for you properly leading to a memory leak.
Personally I recommend that every object who implements IDisposable
should know how to clean itself.
If your factory creates and returns only instances without keeping list of each one, then each class which administrates external resources
or unmanaged resources
should implement IDisposable
.
Upvotes: 0