This is a bit against SO's policy but to extend on Simon`s answer i'll direct you to Mark Seeman's excellent blog post: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
Some of the comments to the blog post are very interesting, too.
Now to address your problem with ninject and extensions - which i assume are unknown to you/the composition root at the time when you write them - i would like to point out the NinjectModule
s. Ninject already features such an extensibility mechanism which is heavily used with/by all ninject.extension.XYZ
dlls.
What you'll do is implement some FooExtensionModule : NinjectModule
classes in your extensions. The Modules contain the Bind
methods. Now you'll tell ninject to load all Modules from some .dll's. That's it.
It's explained in far more greater detail here: https://github.com/ninject/ninject/wiki/Modules-and-the-Kernel
Drawbacks:
- Extensions depend on Ninject
- you may need to recompile your extensions when you "update ninject"
- as the software grows, it will make it more and more expensive to switch DI containers
- When using
Rebind
issues may arise which are difficult to track down (well this is the case whether your using Modules or not.)
- Especially when extension-developers don't know about other extensions, they might create identical or conflicting bindings (such as
.Bind<string>().ToConst("Foo")
and .Bind<string>().ToConst("Bar")
). Again, this is also the case when you're not using Modules, but extensions add one more layer of complexity.
Advantage:
- simple and to the point, there's no extra layer of complication/abstraction which you'd need to abstract the container away.
I've used the NinjectModule
approach in a not-so-small Application (15k unit/component tests) with a lot of success.
If all you need are simple bindings like .Bind<IFoo>().To<Foo>()
without scopes and so on, you might also consider using a simpler system like putting attributes on classes, scanning for these, and creating the bindings in the composition root. This approach is way less powerful but because of that it is much more "portable" (adaptable to be used with other DI container), too.
Dependency Injection an late instantiation
the idea of composition root is, that (whenever possible) you create all objects (the entire object graph) in one go. For example, in the Main
method you might have kernel.Get<IMainViewModel>().Show()
.
However, sometimes this is not feasible or appropriate. In such cases you will need to use factories. There's actually a bunch of answers to this regard on stackoverflow already.
There's three basic types:
- To create an an instance of
Foo
which requires instances of Dependency1
and Dependency2
(ctor injected), create a class FooFactory
which gets one instance of Dependency1
and Dependency2
ctor injected itself. The FooFactory.Create
method will then do new Foo(this.dependency1, this.dependency2)
.
- use ninject.extensions.Factory:
- use
Func<Foo>
as a factory: you can have a Func<Foo>
injected and then call it to crate an instance of Foo
.
- use interfaces and
.ToFactory()
binding (i recommend this approach. Cleaner code, better testability). For example: IFooFactory
with method Foo Create()
. Bind it like: Bind<IFooFactory>().ToFactory();
Extensions which replace Implementations
IMHO this is not one of the goals of dependency-injection containers. That doesn't mean it's impossible, but it just means you've got to figure it out yourself.
The simplest you could to with ninject would be to use .Rebind<IFoo>().To<SomeExtensionsFoo>()
. However, as stated before, that's a bit brittle. If the Bind
and Rebind
are executed in the wrong sequence, it fails. If there's multiple Rebind
s, the last will win - but is it the correct one?
So let's take it one step further. Imagine:
`.Bind<IFoo>().To<SomeExtensionsFoo>().WhenExtensionEnabled<SomeExtension>();`
you can devise your own custom WhenExtensionEnabled<TExtension>()
extension method which extends the When(Func<bool> condition)
syntax method.
You'll have to devise a way to detect whether an extension is enabled or not.