Skip to content

Factory interface: Referencing Named Bindings

Floyd May edited this page Oct 29, 2015 · 14 revisions

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");

Using NamedLikeFactoryMethod extension method to get name directly from factory method

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.

Using WhenAnyAncestorNamedLikeFactoryMethod to define conditional bindings on factory methods

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

Example customisation: Treating the first factory method parameter as a name specifier

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());