Skip to content

Optional Bindings and Null Object Pattern

Philipp Dolder edited this page Mar 20, 2014 · 3 revisions

By default, ninject StandardKernel will throw an ActivationException in case one requests a type where no binding is available and which is not self bindable. For example:

public interface IWeapon
{
    void Strike();
}

public class Warrior
{
    private readonly IWeapon weapon;

    public Warrior(IWeapon weapon)
    {
        this.weapon = weapon;
    }

    public void Attack()
    {
        this.weapon.Strike();
    }
}

public class Demo
{
    [Fact]
    public void Demonstrate()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Warrior>().ToSelf();            
        kernel.Get<Warrior>();
    }
}

Here, kernel.Get<Warrior>() will throw:

Error activating IWeapon
No matching bindings are available, and the type is not self-bindable.
Activation path:
  2) Injection of dependency IWeapon into parameter weapon of constructor of type Warrior
  1) Request for Warrior

Suggestions:
  1) Ensure that you have defined a binding for IWeapon.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.

Making the binding optional

You can tell ninject to not throw, but inject null values instead. This is done by setting AllowNullInjection on the NinjectSettings to true:

var kernel = new StandardKernel( 
    new NinjectSettings
    {
        AllowNullInjection = true
    });

However, we now have to adapt the implementation of Warrior.Attack() to:

public void Attack()
{
    if (this.weapon != null)
    {
        this.weapon.Strike();
    }
}

Or Attack()ing would fail with a NullReferenceException. But hold on, the null object pattern is coming to your rescue!

Null Object Pattern

(Also see Wikipedia) With the null object pattern, instead of handling nulls all over the place, you are creating a "null" implementation of the interface instead:

public class NullWeapon : IWeapon
{
    public void Strike()
    {
        // i'm the lazy null! I'm really not doing anything but watching 0s and 1s pass by all day long, imagine what a happy life!
    }
}

now add a binding:

kernel.Bind<IWeapon>().To<NullWeapon>();

And remove the if from the Warrior.Attack() method:

public void Attack()
{
    this.weapon.Strike();
}

Conditional Bindings

Of course, having a null IWeapon is only useful if sometimes there is a concrete weapon, like Sword or Spear, and sometimes it's valid that there is just none. If there always needs to be a specific weapon, you don't need the null object pattern and you don't need a null object! Having said that, let's extend the example a bit:

Let's say we have an application configuration for our game where we specify the era where the game takes place in. Let's say there's:

  • pre-historical: humans didn't invent any weapons yet (well ok, there were no humans)
  • middle-age: Sword it is!
  • future: there must be a LaserGun!

So let's create the bindings:

kernel.Bind<IWeapon>().To<NullWeapon>();
kernel.Bind<IWeapon>().To<Sword>().When(ctx => config.Era == MiddleAge);
kernel.Bind<IWeapon>().To<LaserGun>().When(ctx => config.Era == Future);

this gives us a "default" binding for NullWeapon in case no .When(...) matches, but when a .When(...) matches, well, the matching binding is used!


Also see http://stackoverflow.com/questions/6546657/ninject-optional-injection for a real life example.

Replacing the Null-Object implementation by a proxy

Tired of implementing all the null objects? You could opt to use a proxy instead, see the interception extension!

IResolutionRoot.TryGet and IResolutionRoot.TryGetAndThrowOnInvalidBinding

Sometimes - in very few occasions though - doing a null-check may be simpler then implementing a null object or even several null objects. In these cases you may opt to use the IResolutionRoot.TryGet<T>() or IResolutionRoot.TryGetAndThrowOnInvalidBinding<T>() extension methods. Both return null in case there is no matching binding (the usual rules apply like with constructor injection). However, there is a difference:

  • TryGet<T> will try to instanciate the type in case there is a binding. If the instanciation fails with ActivationException, the exception is swallowed and null is returned.
  • TryGetAndThrowOnInvalidBinding<T> rethrows the ActivationException in case there is a matching binding.

Thus, TryGet<T> may hide configuration issues.