I've been experimenting with the SimpleServiceLocator, and I like it quite a bit, but there's one thing that I'm really frustrated by--you can't use automatic constructor injection for singletons. To make matters worse, you can't even use automatic constructor injection for its dependencies. You have to create the singleton object, all it's dependencies, all its dependencies dependencies, etc. manually.
Why is SimpleServiceLocator designed this way?
Aren't singletons supposed to be just like regular instances except that, upon the first request for an instance, that instance is stored and reused instead of a new one being created each time? Why does SimpleServiceLocator require an instance to be provided during the registration process rather than just allow the instance to be created and stored on first request?
I get that the point of SimpleServiceLocator is to not have a lot of bells and whistles and be really easy for beginners to use, but it seems like it's just designed incorrectly, and that the method for registering a singleton should be identical to the method for registering a regular instance except that the method name should be RegisterSingle<T>()
instead of Register<T>()
. Is there a reason for the more complicated (and seemingly less convenient) design I'm just not getting?
Meanwhile, is there another (preferably free) IOC container I can use that let's me register objects in code similarly to the SimpleServiceLocator but does allow automatic contructor injection for singletons (or at least allows automatic constructor injection for the dependencies of the singleton)?
The
RegisterSingle<T>
method is just a fancy helper method just to make life easier. What you can do withRegisterSingle<T>
can also be done with theRegister<T>
method. The web site gives examples of this. You can register a single instance using theRegister<T>
method as follows (it uses a closure):When you look at the lifestyle management examples on the web site, you can see the following example for creating a thread static instance:
I think this is the power of simplify, because there is almost nothing you can't do with this pattern. What you are trying to achieve is a bit harder, I must admit this, but nothing really advanced IMO. Here is the code you need to solve your problem:
The trick is here to store the instance in a static variable (just as with the thread static), but now you should not create the instance yourself by
new
ing it up, but you delegate the creation to the Simple Service Locator. This works, because –as you know- the SimpleServiceLocator will do automatic constructor injection when a concrete type is requested.I must admit that it is a shame that we need to do this trickery. It would be nice if the library could actually do this for us. For instance, I can imagine a
RegisterSingle<T>
overload being added that allows us to do the following:Please let me know what you think of such an overload. I'm always interested in feedback to make the library better. This would certainly be a nice feature for the next release.
Update:
Since release 0.14 we can do the following:
It won't get any easier than this.
Cheers
A typical singleton implementation has a
private
constructor, so the container cannot "see" it, call it, or detect dependencies.Perhaps you are referring to the lifetime management features of some IoC containers, where you can configure the container to always return the same single instance of a class.
This is not what singleton means. Although the container returns the same instance, nothing prevents you from instantiating an instance in code using
new
.A singleton, on the other hand, can only ever be instantiated once from any source (once per thread in some implementations). It does not expose a public constructor, rather a static method such as:
As you can see, you can't call
new MySingleton()
from outside the class itself. To "instantiate" the a MySingleton, you have to callMySingleton.GetMySingleton(thing)
. This call returns the sole instance or creates and then returns it.SimpleServiceLocator
has no way of knowing how to create this object, or from where to detect its dependencies.This ability could be added if the API exposed something like
…in which case you could call
Register(() => MySingleton.GetMySingleton());
, but this would only work without parameters. There would have to be more overloads:…so that the container would know what dependencies to instantiate and pass to the specified factory method.
All that said, it doesn't really make sense to have dependency injection with a singleton. Each subsequent call to
GetMySingleton
would have to ignore the arguments or alter the state of the singleton, which is almost certainly a very bad idea.