-
Notifications
You must be signed in to change notification settings - Fork 2
Constructor Injection
Constructor Injection is an another common implementation of Dependency Injection pattern. It allows to configure object by injecting its dependencies using class constructor. Spring.FluentContext gives possibility to configure bindings for constructor arguments.
The BindConstructorArg() methods determines the constructor argument which will be used for binding and offers the same binding options as BindProperty() method.
The constructor parameter can be determined by type or either type and index.
The following example shows binding to constructor arguments by type only:
class PersonWithCat
{
PersonWithCat(string name, Cat cat) { /* ... */ }
/* ... */
}
ctx.RegisterDefault<Cat>()
.BindConstructorArg<string>().ToValue("Kitty");
ctx.RegisterDefault<PersonWithCat>()
.BindConstructorArg<Cat>().ToRegisteredDefault()
.BindConstructorArg<string>().ToValue("Josephine");
As it is presented in example, the order of bound constructor arguments does not matter. Dependencies will be resolved properly.
The following example shows binding to constructor arguments by type and argument index:
ctx.RegisterDefault<PersonWithCat>()
.BindConstructorArg<string>(0).ToValue("Josephine")
.BindConstructorArg<Cat>(1).ToRegisteredDefault();
There is also a possibility to bind constructor arguments in more explicit way, by selecting constructor using UseConstructor() method, and binding to subsequent arguments using BindConstructorArg() method.
ctx.RegisterDefault<PersonWithCat>()
.UseConstructor((string name, Cat cat) => new PersonWithCat(name, cat))
.BindConstructorArg().ToValue("Josephine")
.BindConstructorArg().ToRegisteredDefault();
The advantage of UseConstructor() method is that the number and exact types of constructor arguments are exactly determined for further bindings, so each subsequent call of BindConstructorArg() allows only to bind object of corresponding argument type. It is also not possible to bind more arguments than the ones used in UseConstructor() method, or skip some and move to next configuration step of the given object. Also, all refactorings applied to the constructor and its parameters are also reflected in object configuration, which makes all dependency changes immediately visible.
This method of constructor injection uses the same mechanism as the former methods, so even if UseConstructor() method defines arguments in different order than referenced constructor, but their types allow to map them in unambiguous way, the constructor will be called properly.
There is an example illustrating this case:
ctx.RegisterDefault<PersonWithCat>()
.UseConstructor((Cat cat, string name) => new PersonWithCat(name, cat))
.BindConstructorArg().ToRegisteredDefault()
.BindConstructorArg().ToValue("Josephine");
Please note that UseConstructor() method uses lambda expression only to determine arguments' number and their types. It is not used for object instantiation, so in order to call proper constructor, the lambda parameters has to correspond to the ones used in constructor.
Please also note that usage of this method is limited up to 4 parameter constructors and does not work for abstract types configured to use lookup method injections - it is recommended using the former methods of constructor injection in such cases.
Continue reading: 7. Lookup Method Injection