I want to register a singleton class against its corresponding interface. I found two different ways to achieve this:
Option 1:
this.For<ISomeClass>()
.Use<SomeClass>()
.Singleton();
Option 2:
this.For<ISomeClass>()
.Use(c=>c.GetInstance<SomeClass>())
.Singleton();
this.ForConcreteType<SomeClass>()
.Configure
.Singleton();
So are these two calls identical or is there a difference between the two? Obviously option 1 is much more desirable due to its terseness.
The outcome will be identical, but the second example performs an extra step. It's really small. But the simpler syntax is better.
The first example says that when there's a need for ISomeClass
, fulfill it with SomeClass
. If an instance has been created, use it. If not, create an instance.
The second example says that when there's a need for ISomeClass
, fulfill it by calling an anonymous function which will return an implementation of ISomeClass
. That function resolves and returns an instance of SomeClass
.
Given the amount of work that's going on under the hood, calling one more anonymous function isn't going to make that much difference.
The bigger concern is how the more complex approach can confuse other developers and create problems. This is not hypothetical. I've seen it, and it the consequences aren't pretty.
The developer coming behind you may not understand how an IoC container is supposed to work, and all they can do is follow your example until they understand it. So it's important to set the right example or else they can completely miss the point. I've seen factory methods like this:
this.For<ISomeClass>()
.Use(c=> new SomeClass(
c.GetInstance<ISomethingElse>(),
c.GetInstance<ISomeOtherThing>(),
c.GetInstance<ITenMoreOfThese>()
));
Then they start creating objects like this, resolving instances, and using the DI registration to inject instances into objects. Granted there are occasional valid reasons to do that. But it can pollute your IoC code until it's painful to change the dependencies of a class, which is one of the problems that the container was supposed to solve.
That actually snowballs some more. Now developers don't want to touch the increasingly fragile and confusing IoC code, so they stop creating new classes, start cramming new functionality into existing methods, and never refactor anything. The IoC, which should make refactoring and smaller classes and interfaces easier, ends up making it all harder. That leads to all sorts of new code smells and rot.
So I'd recommend the "no broken window" approach - use the simplest syntax that follows the original intent of the IoC - specify an implementation type for an interface wherever possible instead of a function that resolves and returns an implementation.