2

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();
    }
}
walts81
  • 21
  • 1
  • Suggestion: Add ninject.extensions.ContextPreservation and see if it still behaves the same way. – BatteryBackupUnit Sep 16 '14 at 06:21
  • That gets me closer. And if I were asking Ninject to provide me the OnLandLazy class type explicitly, it would work. Unfortunately I'm asking Ninject for an IAttack using the "onLandLazy" named binding. So the request as far as Ninject is concerned is of type IAttack (not OnLandLazy). So according to the ContextPreservation example, there doesn't seem to be a way to register the binding with the correct info to tie it back to the correct concrete type. EDIT: also even if it did work, that would require me to make specific bindings for Lazy scenarios which I would rather avoid. – walts81 Sep 16 '14 at 14:57
  • you might want to report an issue here: https://github.com/ninject/ninject.extensions.factory/issues – BatteryBackupUnit Sep 17 '14 at 04:55

0 Answers0