Reputation: 1087
I'm attempting to inject a property using ninject
. Given the two bindings in the ninject
module below, I would expect the ConcreteDependency
to be injected into B
.
However, it seems that WhenInjectedInto
doesn't consider the type being injected into, just the declaring type of the target (property in this case).
Is there a way to achieve the behaviour I expected?
static void Main(string[] args)
{
var kernel = new StandardKernel(new TestModule());
var b = kernel.Get<B>();
var c = kernel.Get<C>();
}
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IDependency>().To<EmptyDependency>();
Bind<IDependency>().To<ConcreteDependency>().WhenInjectedInto<B>();
}
}
abstract class A
{
[Inject]
public IDependency Dependency { get; set; }
}
class B : A {}
class C : A {}
interface IDependency {}
class EmptyDependency : IDependency { }
class ConcreteDependency : IDependency { }
Upvotes: 7
Views: 5053
Reputation: 554
In order to check against a concrete type, you can use ParentContext.Plan.Type
on the IRequest
interface. This should give you the behaviour you expected from WhenInjectedInto
. For example:
When(req => req.ParentContext.Plan.Type == typeof(B))
Upvotes: 4
Reputation: 23646
You should use constructor injection instead of property injection if possible. This is a better technique, which is recommended by Mark Seeman, because makes dependencies required for object construction explicit and object signature via constructor is more expressive. Code should look like this:
abstract class A
{
public IDependency Dependency { get; private set; }
public A (IDependency dependency)
{
Dependency = dependency;
}
}
class B : A
{
public B (IDependency dependency)
: base(dependency)
{
}
}
class C : A
{
public C (IDependency dependency)
: base(dependency)
{
}
}
interface IDependency { }
class EmptyDependency : IDependency { }
class ConcreteDependency : IDependency { }
Configuration will be the same as in you example. The following test passes
[Test]
public void TestSpecificBindingToObjectB()
{
var kernel = new StandardKernel(new TestModule());
var b = kernel.Get<B>();
var c = kernel.Get<C>();
Assert.AreNotEqual(b.Dependency.GetType(), c.Dependency.GetType());
Assert.AreEqual(typeof(ConcreteDependency), b.Dependency.GetType());
}
If you have an optional dependency with default implementation and you are ok with decorating your classes with Inject
attribute, you can can pull parent information from request, like this:
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IDependency>().To<EmptyDependency>();
Bind<IDependency>().To<ConcreteDependency>().When(req =>req.ParentContext.Request.Service == typeof(B));
}
}
Then the same test given above passes for your class hierarchy with property injection.
Upvotes: 8