Ninject issue with contextual binding and Lazy<T>

171 Views Asked by At

Ninject doesn't seem to correctly use WhenInjectedInto contstraint while also using Lazy<T>. Check the following example. The OnLandAttack and the OnLandAttackLazy should each be using the Samurai instance. But the Lazy<T> version ends up with the SpecialNinja instance. I'm guessing it's because it's not actually initialized in the contructor? But the type should still be correctly registered I would think. Am I missing something? FYI, this is using Ninject 3.2.2 and the Ninject.Extensions.Factory extension 3.2.1

class Program
{
    static void Main(string[] args)
    {
        var kernel = new StandardKernel();
        kernel.Load(new WarriorModule());

        var amphibious = kernel.Get<IAttack>("amphibious");
        amphibious.Execute();

        var onLand = kernel.Get<IAttack>("onLand");
        onLand.Execute();

        var onLandLazy = kernel.Get<IAttack>("onLandLazy");
        onLandLazy.Execute();

        Console.ReadKey();
    }
}

public class WarriorModule : NinjectModule
{
    public override void Load()
    {
        Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttack>();
        Bind<IWarrior>().To<Samurai>().WhenInjectedInto<OnLandAttackLazy>();
        Bind<IWarrior>().To<SpecialNinja>(); // <-- for everything else

        Bind<IAttack>().To<AmphibiousAttack>().Named("amphibious");
        Bind<IAttack>().To<OnLandAttack>().Named("onLand");
        Bind<IAttack>().To<OnLandAttackLazy>().Named("onLandLazy");
    }
}


public interface IWarrior
{
    void Attack();
}

public class Samurai : IWarrior
{
    public void Attack()
    {
        Console.WriteLine("\tSamurai Attack");
    }
}

public class SpecialNinja : IWarrior
{
    public void Attack()
    {
        Console.WriteLine("\tSpecial Ninja Attack");
    }
}

public interface IAttack
{
    void Execute();
}

public class OnLandAttack : IAttack
{
    private readonly IWarrior warrior;

    public OnLandAttack(IWarrior warrior)
    {
        this.warrior = warrior;
    }

    public void Execute()
    {
        Console.WriteLine("Begin OnLand attack");
        this.warrior.Attack();
    }
}

public class OnLandAttackLazy : IAttack
{
    private readonly Lazy<IWarrior> warrior;

    public OnLandAttackLazy(Lazy<IWarrior> warrior)
    {
        this.warrior = warrior;
    }

    public void Execute()
    {
        Console.WriteLine("Begin OnLandLazy attack");
        this.warrior.Value.Attack();
    }
}

public class AmphibiousAttack : IAttack
{
    private readonly IWarrior warrior;

    public AmphibiousAttack(IWarrior warrior)
    {
        this.warrior = warrior;
    }

    public void Execute()
    {
        Console.WriteLine("Begin Amphibious attack");
        this.warrior.Attack();
    }
}
0

There are 0 best solutions below