-
Notifications
You must be signed in to change notification settings - Fork 35
Factory interface: Referencing Named Bindings
In some cases when employing an Abstract Factory using the extension, one wants to use a specific Named Binding (i.e., where the Bind<T>
expression terminates in a .Named("name")
subexpression). The default instance provider of the extension uses a convention of attempting to resolve an instance based on a named binding whenever the name of the method declaration on the abstract factory interface method starts with “Get”. For instance:-
IFoo GetMySpecialFoo()
leads to the internally generated code performing the equivalent of the following resolution call:
resolutionRoot.Get<Foo>("MySpecialFoo");
Instead of specifying a string in the named binding like in the example above, you can use the extension method NamedLikeFactoryMethod
.
For example, if you have a factory like this:
public interface IFooFactory
{
IFoo GetMySpecialFoo();
}
Instead of defining the binding with a name specified by a string:
kernel.Bind<IFoo>().To<Foo>().Named("MySpecialFoo")
You can write:
kernel.Bind<IFoo>().To<Foo>().NamedLikeFactoryMethod((IFooFactory f) => f.GetMySpecialFoo())
This makes the naming convention explicit and therefore is easier to refactor.
Imagine the scenario that you want to use a different instance as a dependency depending on the factory method that created the tree of instances. You can define a constraint on a binding with WhenAnyAncestorNamedLikeFactoryMethod
that is met only when any ancestor (instances above in the dependency tree of instances) was created over a named binding with the name of the factory method (typically by using NamedLikeFactoryMethod
explained above).
For example:
public interface IFooFactory
{
IFoo GetMySpecialFoo();
}
public class Foo : IFoo
{
public Foo(IBar bar) {}
}
kernel.Bind<IFoo>().To<Foo>().NamedLikeFactoryMethod((IFooFactory f) => f.GetMySpecialFoo())
kernel.Bind<IBar>().To<Bar>().WhenAnyAncestorNamedLikeFactoryMethod((IFooFactory f) => f.GetMySpecialFoo())
Now, when an instance of Foo
is created over the factory the condition of the binding from IBar
to Bar
is met and an instance of Bar
is injected into Foo
. If an instance of Foo
is created otherwise, no compatible IBar
will be found.
This gives you a refactoring safe way to define conditional bindings on factory methods
If you wish to control the binding name based on a string in your code rather than this convention, this can be achieved by hooking in a custom instance provider implemented as follows:-
class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
protected override string GetName(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
return (string)arguments[0];
}
protected override Ninject.Parameters.IConstructorArgument[] GetConstructorArguments(System.Reflection.MethodInfo methodInfo, object[] arguments)
{
return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
}
}
using the following Binding expression syntax:-
this.Bind<IMyFactory>().ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());