简体   繁体   中英

Ninject - overloads for WithConstructorArgument behave weird

I have the following code:

namespace Test.Ninject.ConstructorArgumentBug
{

public class ClassA
{
    private readonly IDependecy _dependecy;

    public ClassA(IDependecy dependecy)
    {
        _dependecy = dependecy;
    }
}

public interface IDependecy
{
}

public class ConcreteDependency : IDependecy
{
    private readonly string _arg;

    public ConcreteDependency(string arg)
    {
        _arg = arg;
    }
}

public class Tests
{
    [Test]
    public void Test1()
    {
        var kernel = new StandardKernel();
        kernel.Bind<IDependecy>()
            .To<ConcreteDependency>()
            .WhenInjectedInto<ClassA>()
            .WithConstructorArgument(new ConstructorArgument("arg", "test"));

        var classA = kernel.Get<ClassA>();
        Assert.IsNotNull(classA);
    }

    [Test]
    public void Test2()
    {
        var kernel = new StandardKernel();
        kernel.Bind<IDependecy>()
            .To<ConcreteDependency>()
            .WhenInjectedInto<ClassA>()
            .WithConstructorArgument("arg", "test");

        var classA = kernel.Get<ClassA>();
        Assert.IsNotNull(classA);
    }
}
}

The Test1 doesn't work, but the Test2 does, and I believe they should behave the same. It looks like a bug to me. For some reason the first test cannot resolve dependency with the following error:

Ninject.ActivationException : Error activating string No matching bindings are available, and the type is not self-bindable. Activation path: 3) Injection of dependency string into parameter arg of constructor of type ConcreteDependency 2) Injection of dependency IDependecy into parameter dependecy of constructor of type ClassA 1) Request for ClassA

I guess if the first test fails the second should fail too. Am I doing something wrong?

Thanks!

In Test1 , the WithConstructorArgument method that you are invoking has the following signature:

IBindingWithOrOnSyntax<T> WithConstructorArgument<TValue>(TValue value);

Here is what the documentation says about this method (you get this on IntelliSense):

Indicates that the specified constructor argument should be overridden with the specified value.

And here is the documentation for TValue :

Specifies the argument type to override

And here is the documentation for value :

The value for the argument

So, this line:

.WithConstructorArgument(new ConstructorArgument("arg", "test"));

Which is equivalent to (C# automatically infers TValue ):

.WithConstructorArgument<ConstructorArgument>(new ConstructorArgument("arg", "test"));

is telling NInject that the constructor of ConcreteDependency has a parameter of type ConstructorArgument , where in fact it has a parameter of type string .

So you should change it to

.WithConstructorArgument<string>("test");

Or simpler:

.WithConstructorArgument("test");

Please note that there is no overload of WithConstructorArgument that has a parameter of type ConstructorArgument .

However, there is another method called WithParameter that takes in an IParameter .

Since ConstructorArgument implements IParameter , you can use this method to specify the constructor argument via ConstructorArgument like this:

kernel.Bind<IDependecy>()
    .To<ConcreteDependency>()
    .WhenInjectedInto<ClassA>()
    .WithParameter(new ConstructorArgument("arg", "test"));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM