One thing that makes me squirm a little with DI is the assumption that all injected objects are cheap to instantiate and produce no side effects -OR- the dependency is used so frequently that it outweighs any associated instantiation cost.
Where this is can be significant is when a dependency is not frequently used within a consuming class; such as something like an IExceptionLogHandlerService
. Obviously, a service like this is invoked (hopefully :)) rarely within the class - presumably only on exceptions needing to be logged; yet the canonical constructor-injection pattern...
Public Class MyClass
Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService
Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
Me.mExLogHandlerService = exLogHandlerService
End Sub
...
End Class
...requires that a "live" instance of this service be provided, damned the cost/side-effects required to get it there. Not that it likely would, but what if constructing this dependency instance involved a service/database hit, or config file look-ups, or locked a resource until disposed of? If this service was instead constructed as-needed, service-located, or factory-generated (all having problems their own), then you would be taking the construction cost only when necessary.
Now, it is a generally accepted software design principle that constructing an object is cheap and doesn't produce side-effects. And while that's a nice notion, it isn't always the case. Using typical constructor-injection however basically demands that this is the case. Meaning when you create an implementation of a dependency, you have to design it with DI in mind. Maybe you would have made object-construction more costly to obtain benefits elsewhere, but if this implementation is going to be injected, it will likely force you to reconsider that design.
By the way, certain techniques can mitigate this exact issue by allowing lazy-loading of injected dependencies, e.g. providing a class a Lazy<IService>
instance as the dependency. This would change your dependent objects' constructors and make then even more cognizant of implementation details such as object construction expense, which is arguably not desirable either.