How Ninject chooses the right constructor to use?

1,275 views
Skip to first unread message

Padcom

unread,
Apr 19, 2009, 8:43:49 AM4/19/09
to ninject
Hi all,

please consider the following example:

class Dependency { }

class Container {
private readonly Dependency dep;
public Container() { }
public Container(Dependency dep) { this.dep = dep; }
}

class Program {
static void Main(string[] args) {
IKernel kernel = new StandardKernel();
Container instance = kernel.Get<Container>();
}
}

I'm trying to find out how does the framework choose the constructor
to use. In the example above the parameter-less constructor is used
but it seems quite obvious that the second one should be used. If I
remove the parameter-less constructor the second one is used so it is
obviously possible.

I know about the [Inject] attribute but having the option not to
include dependencies on the framework itself would be of great value
to me.

Best regards,
Matthias.

Ian.F...@gmail.com

unread,
Apr 19, 2009, 8:46:44 AM4/19/09
to nin...@googlegroups.com
From what I remember, Ninject tries to pick the most complex .ctor for which it can satisfy all dependencies. It weighs the .ctors while processing the request and picks the .ctor
with the highest weight.

-Ian

On Apr 19, 2009 5:43am, Padcom <pad...@gmail.com> wrote:
>
>
> Hi all,
>
>
>
> please consider the following example:
>
>
>
>        class Dependency { }
>
>
>
>        class Container {
>
>                private readonly Dependency dep;
>
>                public Container() { }
>
>                public Container(Dependency dep) { this.dep = dep; }
>
>        }
>
>
>
>        class Program {
>
>                static void Main(string[] args) {
>
>                        IKernel kernel = new StandardKernel();
>
>                        Container instance = kernel.Get();

Padcom

unread,
Apr 19, 2009, 8:54:50 AM4/19/09
to ninject
If that'd be the case then the second constructor should have been
taken instead and that is what I'd expect to be the default behavior.

Anyways, I've changed the code to be more explicit about the
dependencies but still get the same result which is that the parameter-
less constructor is being called:

class Dependency { }

class Container {
private readonly Dependency dep;
public Container() { }
public Container(Dependency dep) { this.dep = dep; }
}

class Program {
static void Main(string[] args) {
IKernel kernel = new StandardKernel(new InlineModule(x => {
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf();
}));
Container instance = kernel.Get<Container>();
}
}

Any ideas?

Best regards,
Matthias

Ian.F...@gmail.com

unread,
Apr 19, 2009, 9:13:45 AM4/19/09
to nin...@googlegroups.com
In Ninject 1 you have to use the AutoWiringModule in order for Ninject to resolve the dependency .ctor. In Ninject 2, it will resolve the instances
without the need for the extra module.


[TestFixture]
public class CtorFixture
{
private class Dependency
{
}

private class Container
{
private readonly Dependency dep;

public Container()
{
}

public Container( Dependency dep )
{
this.dep = dep;
}

public Dependency Dep
{
get { return dep; }
}
}

[Test]
public void CtorWithResolvableDependenciesShouldBeUsed()
{
using ( var kernel = new StandardKernel( new InlineModule( x =>
{
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf();
} ), new AutoWiringModule() ) )
{
var container = kernel.Get<Container>();
Assert.That( container.Dep, Is.Not.Null );
}
}

[Test]
public void DefaultCtorShouldBeUsed()
{
using ( var kernel = new StandardKernel( new InlineModule( x =>
{
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf();
} ) ) )
{
var container = kernel.Get<Container>();
Assert.That( container.Dep, Is.Null );
}
}
}


-Ian

Padcom

unread,
Apr 19, 2009, 9:21:36 AM4/19/09
to ninject
Thanks for the info about AutoWiringModule. I've tried it out but with
no joy.

I guess I'll just stop fooling around with multiple constructors as it
makes little sense in my case anyways.


Best regards,
Matthias.

Ian.F...@gmail.com

unread,
Apr 19, 2009, 9:33:40 AM4/19/09
to nin...@googlegroups.com
Does that test fixture fail for you? It should work.

-Ian

On Apr 19, 2009 6:21am, Padcom <pad...@gmail.com> wrote:
>
>
> Thanks for the info about AutoWiringModule. I've tried it out but with
>
> no joy.
>
>
>
> I guess I'll just stop fooling around with multiple constructors as it
>
> makes little sense in my case anyways.
>
>
>
>
>
> Best regards,
>
> Matthias.
>
>
>
> On Apr 19, 3:13 pm, Ian.F.Da...@gmail.com wrote:
>
> > In Ninject 1 you have to use the AutoWiringModule in order for Ninject to  
>
> > resolve the dependency .ctor. In Ninject 2, it will resolve the instances
>
> > without the need for the extra module.
>
> >
>
> > [TestFixture]
>
> > public class CtorFixture
>
> > {
>
> > private class Dependency
>
> > {
>
> >
>
> > }
>
> >
>
> > private class Container
>
> > {
>
> > private readonly Dependency dep;
>
> >
>
> > public Container()
>
> > {
>
> >
>
> > }
>
> >
>
> > public Container( Dependency dep )
>
> > {
>
> > this.dep = dep;
>
> >
>
> > }
>
> >
>
> > public Dependency Dep
>
> > {
>
> > get { return dep; }
>
> >
>
> > }
>
> > }
>
> >
>
> > [Test]
>
> > public void CtorWithResolvableDependenciesShouldBeUsed()
>
> > {
>
> > using ( var kernel = new StandardKernel( new InlineModule( x =>
>
> > {
>
> > x.Bind().ToSelf();
>
> > x.Bind().ToSelf();} ), new AutoWiringModule() ) )
>
> >
>
> > {
>
> > var container = kernel.Get();
>
> > Assert.That( container.Dep, Is.Not.Null );
>
> >
>
> > }
>
> > }
>
> >
>
> > [Test]
>
> > public void DefaultCtorShouldBeUsed()
>
> > {
>
> > using ( var kernel = new StandardKernel( new InlineModule( x =>
>
> > {
>
> > x.Bind().ToSelf();
>
> > x.Bind().ToSelf();} ) ) )
>
> >
>
> > {
>
> > var container = kernel.Get();

Ian.F...@gmail.com

unread,
Apr 19, 2009, 10:25:15 AM4/19/09
to nin...@googlegroups.com
There are two tests in my example. One with and one without the AutoWiringModule. The test with the AutoWiringModule shows the dependency
is injected.

-Ian

On Apr 19, 2009 7:02am, pad...@gmail.com wrote:
> The fixture tests if Dep is null and it is. However the idea was that you get Dep injected using the more complex constructor.
> > &gt
> >
> >
> >
> >
> >

Padcom

unread,
Apr 19, 2009, 10:49:44 AM4/19/09
to ninject
Ok, now I've been mistaken. The fixture you provided works.

What I've been trying to accomplish next (and that's the reason why I
got a bit confused) is as follows:

[TestFixture]
public class CtorFixture {
private class Dependency {
}
private class Container {
private readonly Dependency dep;
private readonly String value;

public Container() {
}

public Container(Dependency dep) {
this.dep = dep;
}

public Container(Dependency dep, String value) {
this.dep = dep;
this.value = value;
}
public Dependency Dep {
get { return dep; }
}

public String Value {
get { return value; }
}
}

[Test]
public void CtorWithResolvableDependenciesAndStringParamShouldBeUsed()
{
using (var kernel = new StandardKernel(new InlineModule(x => {
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf().WithConstructorArgument(
"value", "Hello, world!");
}), new AutoWiringModule())) {
var container = kernel.Get<Container>();
Assert.That(container.Dep, Is.Not.Null);
Assert.That(container.Value, Is.EqualTo("Hello, world!"));
}
}

[Test]
public void CtorWithResolvableDependenciesShouldBeUsed() {
using (var kernel = new StandardKernel(new InlineModule(x => {
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf();
}), new AutoWiringModule())) {
var container = kernel.Get<Container>();
Assert.That(container.Dep, Is.Not.Null);
}
}

[Test]
public void DefaultCtorShouldBeUsed() {
using (var kernel = new StandardKernel(new InlineModule(x => {
x.Bind<Dependency>().ToSelf();
x.Bind<Container>().ToSelf();
}))) {
var container = kernel.Get<Container>();
Assert.That(container.Dep, Is.Null);
}
}
}

In this case test case CtorWithResolvableDependenciesShouldBeUsed
works but CtorWithResolvableDependenciesAndStringParamShouldBeUsed
fails.
Do you have any idea on how to force the third constructor to be used?

Best regards,
Matthias.

On Apr 19, 4:25 pm, Ian.F.Da...@gmail.com wrote:
> There are two tests in my example. One with and one without the  
> AutoWiringModule. The test with the AutoWiringModule shows the dependency
> is injected.
>
> -Ian
>
> On Apr 19, 2009 7:02am, pad...@gmail.com wrote:
>
> > The fixture tests if Dep is null and it is. However the idea was that you  
> > get Dep injected using the more complex constructor.

Ian.F...@gmail.com

unread,
Apr 19, 2009, 11:22:00 AM4/19/09
to nin...@googlegroups.com
Ok, so here is what is going on.

I can get your code to run fine if I remove the .ctor :public Container(Dependency dep)

What is happening is that the heuristic is counting the parameters for which it has bindings, but ignores the .ctor arguments in its counting.
The .ctor argument is only used during activation instead of activation & selection.

Given this Container(Dependency dep) and Container(Dependency dep, string value) have the same score.

BUT!!

Ninject defaults to the first member with the highest score. If you reverse the declaration of the .ctors, your test will work fine:

Success:
public Container(Dependency dep, string value)
{
this.dep = dep;
this.value = value;
}

public Container(Dependency dep)
{
this.dep = dep;
}

Failure:
public Container(Dependency dep)
{
this.dep = dep;
}

public Container(Dependency dep, string value)
{
this.dep = dep;
this.value = value;
}


Does that make sense?

-Ian

On Apr 19, 2009 7:49am, Padcom <pad...@gmail.com> wrote:
>
>
> Ok, now I've been mistaken. The fixture you provided works.
>
>
>
> What I've been trying to accomplish next (and that's the reason why I
>
> got a bit confused) is as follows:
>
>
>
> [TestFixture]
>
> public class CtorFixture {
>
> private class Dependency {
>
> }
>
> private class Container {
>
> private readonly Dependency dep;
>
> private readonly String value;
>
>
>
> public Container() {
>
> }
>
>
>
> public Container(Dependency dep) {
>
> this.dep = dep;
>
> }
>
>
>
> public Container(Dependency dep, String value) {
>
> this.dep = dep;
>
> this.value = value;
>
> }
>
> public Dependency Dep {
>
> get { return dep; }
>
> }
>
>
>
> public String Value {
>
> get { return value; }
>
> }
>
> }
>
>
>
> [Test]
>
> public void CtorWithResolvableDependenciesAndStringParamShouldBeUsed()
>
> {
>
> using (var kernel = new StandardKernel(new InlineModule(x => {
>
> x.Bind().ToSelf();
>
> x.Bind().ToSelf().WithConstructorArgument(
>
> "value", "Hello, world!");
>
> }), new AutoWiringModule())) {
>
> var container = kernel.Get();
>
> Assert.That(container.Dep, Is.Not.Null);
>
> Assert.That(container.Value, Is.EqualTo("Hello, world!"));
>
> }
>
> }
>
>
>
> [Test]
>
> public void CtorWithResolvableDependenciesShouldBeUsed() {
>
> using (var kernel = new StandardKernel(new InlineModule(x => {
>
> x.Bind().ToSelf();
>
> x.Bind().ToSelf();
>
> }), new AutoWiringModule())) {
>
> var container = kernel.Get();
>
> Assert.That(container.Dep, Is.Not.Null);
>
> }
>
> }
>
>
>
> [Test]
>
> public void DefaultCtorShouldBeUsed() {
>
> using (var kernel = new StandardKernel(new InlineModule(x => {
>
> x.Bind().ToSelf();
>
> x.Bind().ToSelf();
>
> }))) {
>
> var container = kernel.Get();

Padcom

unread,
Apr 19, 2009, 11:40:31 AM4/19/09
to ninject
Ok I get it.

However after reversing the order of the constructors in the test
fixture I've presented earlier the test you wrote fails. Do you know
of any remedy to that issue or is this a dead end for now?

And like I said previously, I understand that I might be pushing the
framework to do stuff that makes little to no sense. The only place
where it makes sense for me is when I write a unit test where I have
like a default constructor and then I assign mocks on an as-needed
basis. So for example I don't need a data access object in a service
layer implementation if I'm just trying to test the ToString method.
That way I can guard that no-one will add real database call to the
ToString method (because it'll just throw an exception).


Best regards,
Matthias.
Reply all
Reply to author
Forward
0 new messages