We have a large solution (> 100 projects) and almost every type uses either a service locator (example 1) or our own dictionary of types (example 2) for instantiation.
For example we have:
IQuote quote = Registry.Resolve<IQuote>();
or
IQuote quote = Registry.Find<IQuote>(args);
The 2nd example goes off to the config file to find what concrete object to instantiate using reflection.
It makes life more difficult when following through code – because it’s not clear what concrete type is being used – so we have to check the mappings many times as we’re trying to learn a part of the code. Using the above as an example pressing F12 on: quote.DoSomething() would take you to the interface definition.
It’s also a bit more difficult to implement – we need an interface + concrete class + config mappings, when the alternative is just 1 class.
Come to think of it – I’m not aware that anything has ever been “swapped out” for another type – so although we’ve implemented IoC we haven’t used it, or at least – very little.
So – is it actually worth it? Have we implemented it incorrectly / too much? Am I misunderstanding something?
In my opinion, you don’t need to work with each and every class with DI in mind. I would use the following strategy:
The modules should be relatively fine-grained.
There are some common places where you need to use DI, often it’s replaceable data sources and (not so often) algorithms. Use the common sense to check whether something needs to be replaceable or not. Don’t hesitate to throw in an early refactoring if you see something needs DI or suffers from it.