I've recently been reading through Mark Seemann's Dependency Injection in .NET and have been attempting to apply some of what I've learned in a new project I'm working on, and I'm stumped on a particular scenario trying to determine what dependencies I should and should not inject. I've read several other questions on SO and elsewhere that discuss similar scenarios but in a roundabout manner, and I think I've narrowed the underlying conceptual question to that which is in the title:
Can a stable dependency have a volatile dependency? Put another way: If a stable dependency has a volatile dependency, is the stable dependency really stable?
A quick example:
public class MyClass
{
private IVolatileDependency1 _one;
private StableDependency _stable;
public MyClass(IVolatileDependency1 one, IVolatileDependency2 two)
{
_one = one;
_stable = new StableDependency(two)
}
}
public class StableDependency
{
private IVolatileDependency2 _two;
public StableDependency(IVolatileDependency2 two)
{
_two = two;
}
}
In this situation, MyClass
has a stable dependency which I've chosen not to inject but instead instantiate internally and hold via composition. However, that stable dependency has a volatile dependency, which I'm injecting into MyClass
and passing through to StableDependency
's constructor.
For whatever reason, this smells a little bit to me. It's fairly straightforward in such a simple contrived example, but I can see things getting out of hand quickly in a more complicated real-world situation.
Is StableDependency
really stable, or should I be composing/resolving it prior to constructing MyClass
and injecting it from there? I really don't foresee StableDependency
changing or being replaced by another implementation, but on the other hand the practice of passing dependencies down through parent classes to their children (parent/child in the composition sense) seems to expose the details of the children up through the parent, which would be a violation of the Law of Demeter.
EDIT: Changed VolatileDependency1 and VolatileDependency2 to interfaces to clarify that they are intended to be satisfied by multiple possible implementations (LSP-compatible).
EDIT 2: Thinking on this some more, and reading KeithS's answer and default.kramer's comment below, make me realize that maybe I shouldn't have named StableDependency
as I did, because I don't think it's a dependency in the first place. It's not something I ever expect to have multiple implementations for; it's merely an implementation detail that MyClass
uses composition to contain a StableDependency
, so MyClass
's knowledge of how to construct a StableDependency
isn't a problem I don't think. The big question is, StableDependency
does have a dependency on IVolatileDependency2
, so how do I inject that dependency? Do I reason that for all intents and purposes MyClass
has a dependency on IVolatileDependency2
, and the fact that it just passes that dependency down to StableDependency
is an implementation detail unrelated to DI?