Ninject multi-injection is not as greedy as I would have thought! How come?
Asked Answered
M

1

11

If I have a class with a ctor set up for multi-injection like this:

public Shogun(IEnumerable<IWeapon> allWeapons)
{
    this.allWeapons = allWeapons;
}

And bindings set up like this:

Bind<IWeapon>().To<Sword>();
Bind<IWeapon>().To<Dagger>().WhenInjectedInto<Shogun>();

Then I would expect Shogun to be constructed with both weapons injected? But this isn't the case - it only gets the Dagger.

If I add a further binding like this:

Bind<IWeapon>().To<Sword>();
Bind<IWeapon>().To<Dagger>().WhenInjectedInto<Shogun>();
Bind<IWeapon>().To<Shuriken>().WhenInjectedInto<Shogun>();

Then Shogun gets the Dagger and the Shuriken. WhenInjectedInto<T>() looks like it should only be constraining the binding it is applied to and not affecting other bindings. I find this behaviour very misleading.

Can someone explain what is happening here?

Millwright answered 4/9, 2011 at 4:2 Comment(7)
I am sorry, but why would you expect Shogun (in the first case) to be constructed with both weapons injected, when you explicitly are asking to bind IWeapon to Dagger, when injected into Shogun?Davin
Because I have also asked for IWeapon to be bound to Sword. Why should binding IWeapon to Dagger in the specific case prevent the general binding? This means I can write code that makes a specific binding and break more general bindings made elsewhere. It seems dangerous and counter-intuitive.Millwright
But that would beat the purpose of WhenInjectedInto, wouldn't it? I am new to ninject, but as far as I understand, the purpose of this feature is to have specific cases, as you have mentioned, handled. You want IWeapon to be bound to Sword in general; however, when injected into Shogun, you want it to be bound to Dagger. If you want Shogun to have both Sword and Dagger injected, WhenInjectedInto shouldn't be used, IMHO.Davin
While we are in the business of disclaimers, I also am new to Ninject. :) I see what you are saying, and it may just be a matter of opinion - I think the reading of WhenInjectedInto is a little ambigious. I was reading it as refering to the implementation (i.e. Dagger or Sword) rather than the contract (i.e. IWeapon), rather than saying "When injecting IWeapon into Shogun inject a Dagger". Read this way it makes sense.Millwright
I still don't like the way the general bindings are then dropped though. :) I can't help but see it potentially breaking things in an unexpected manner in complex applications.Millwright
So, should I post my comment as an answer, then? :)Davin
I think I'd like to see an answer that explained the mechanics of what is happening in concrete terms. I notice that other When conditions can be applied that seem to combine quite happily with the ones I already have e.g: Bind<IWeapon>().To<BoStaff>().When(x => true); This doesn't mention Shogun at all yet still turns up in the multi-injection when Sword does not.Millwright
C
13

That's a bug - GetAll will not return all instances in case conditional and unconditional bindings are mixed.

It's fixed in version Version 2.4.0.0

Cleavage answered 4/9, 2011 at 22:21 Comment(3)
So I was wrong! (in the comments to the question). Thanks for the question, James and the clarification, Remo!Davin
Nice job! I'm relieved it was a bug and not by design!Millwright
Just to add, at the time of writing the current release version is 2.2.0.0 - so anyone affected by this needs to deliberately grab the latest build.Millwright

© 2022 - 2024 — McMap. All rights reserved.