Get ninject factory extension to allow factory parameters be passed to dependencies

此生再无相见时 提交于 2019-12-06 04:36:33

问题


Using the Ninject Factory extension, you can automatically generate factories, and let the factory pass parameters to the class' constructor. The following test passes:

public interface IBar
{
    int Foo { get; }
}

public class Bar : IBar
{
    int _foo;
    public Bar(int foo) { _foo = foo; }
    public int Foo { get { return _foo; } }
}

public interface IBarFactory
{
    IBar CreateTest(int foo);
}

[Test]
public void ExecuteTest()
{
    var kernel = new StandardKernel();
    kernel.Bind<IBar>().To<Bar>();
    kernel.Bind<IBarFactory>().ToFactory();
    var factory = kernel.Get<IBarFactory>();
    var actual = factory.CreateTest(42);
    Assert.That(actual, Is.InstanceOf<Bar>());
}

However, in my particular problem, I would like it to pass the factory arguments to a dependency of the class I'm constructing, not the class itself, like this:

public interface IBarContainer
{
    IBar Bar { get; }
}

public class BarContainer : IBarContainer
{
    IBar _bar;
    public BarContainer(IBar bar) { _bar = bar; }
    public IBar Bar { get { return _bar; } }
}

public interface ITestContainerFactory
{
    IBarContainer CreateTestContainer(int foo);
}

[Test]
public void ExecuteTestContainer()
{
    var kernel = new StandardKernel();
    kernel.Bind<IBar>().To<Bar>();
    kernel.Bind<IBarContainer>().To<BarContainer>();
    kernel.Bind<ITestContainerFactory>().ToFactory();
    var factory = kernel.Get<ITestContainerFactory>();
    var actual = factory.CreateTestContainer(42);
    Assert.That(actual.Bar, Is.InstanceOf<Bar>());
}

This test fails with the message:

Ninject.ActivationException : Error activating int No matching bindings are available, and the type is not self-bindable. Activation path:
3) Injection of dependency int into parameter foo of constructor of type Bar
2) Injection of dependency IBar into parameter bar of constructor of type BarContainer
1) Request for IBarContainer

Is there a way to make the factory figure out that I want to use the passed 'foo' argument when resolving the 'Bar' dependency?


回答1:


From version 3.2.0 of Ninject.Extensions.Factory this is supported natively, using:

Ninject.Extensions.Factory.TypeMatchingArgumentInheritanceInstanceProvider

You can use it like this:

kernel.Bind<IxxxFactory>()
   .ToFactory(() => new TypeMatchingArgumentInheritanceInstanceProvider());

If you look at the source code, it's based on the previous answer.




回答2:


Hy, The default instance provider does not use constructor arguments which are inherited. You can change this behavior by writing your own instance provider like the following:

public class CustomInstanceProvider : StandardInstanceProvider {
    protected override ConstructorArgument[] 
        GetConstructorArguments(MethodInfo methodInfo, object[] arguments) 
        {
            var parameters = methodInfo.GetParameters();
            var constructorArguments = 
                new ConstructorArgument[parameters.Length];
            for (int i = 0; i < parameters.Length; i++)
            {
                constructorArguments[i] = 
                    new ConstructorArgument
                        (parameters[i].Name, arguments[i], true);
            }
            return constructorArguments;
        }
}

Then you only have to instruct ninject to use your own instead of the provided.

Hope that helps




回答3:


If I'm understanding your question correctly, I believe that this Ninject Wiki article has a good example ( Factory interface ) on how to use the new .ToFactory() binding extension, and how to get those generated factories to even create objects who's constructors have parameters.



来源:https://stackoverflow.com/questions/11224606/get-ninject-factory-extension-to-allow-factory-parameters-be-passed-to-dependenc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!