与Ninject厂扩建Ninject约定为绑定多个类型到一个接口(Ninject Conventio

2019-08-20 04:10发布

我想在标题为SO问题问的情况下扩大Ninject厂扩建绑定多个具体类型到一个接口使用Ninject约定的约定的基于绑定ICar实现。

我工作过的阿基姆撰写公认的答案和他的要点概述了完整的例子。

不同的是,我已经取代了明确的ICar绑定与基于惯例,绑定(或它的企图,至少;)

public class CarModule : NinjectModule
{
    public override void Load()
    {
        Bind<ICarFactory>()
            .ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());

        // my unsuccessful binding
        Kernel.Bind(scanner => scanner
                        .FromThisAssembly()
                        .SelectAllClasses()
                        .InheritedFrom<ICar>()
                        .BindAllInterfaces());
        //Bind<ICar>()
        //    .To<Mercedes>()
        //    .Named("Mercedes");
        //Bind<ICar>()
        //    .To<Ferrari>()
        //    .Named("Ferrari");
    }
}

当我尝试实例化car的测试变量,我得到一个ActivationException

Ninject.ActivationException was unhandled by user code
  Message=Error activating ICar
No matching bindings are available, and the type is not self-bindable.
Activation path:
  1) Request for ICar

Suggestions:
  1) Ensure that you have defined a binding for ICar.
  2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
  3) Ensure you have not accidentally created more than one kernel.
  4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
  5) If you are using automatic module loading, ensure the search path and filters are correct.

  Source=Ninject
  StackTrace:
       at Ninject.KernelBase.Resolve(IRequest request) in c:\Projects\Ninject\ninject\src\Ninject\KernelBase.cs:line 362
       at Ninject.ResolutionExtensions.GetResolutionIterator(IResolutionRoot root, Type service, Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 263
       at Ninject.ResolutionExtensions.Get(IResolutionRoot root, Type service, String name, IParameter[] parameters) in c:\Projects\Ninject\ninject\src\Ninject\Syntax\ResolutionExtensions.cs:line 164
       at Ninject.Extensions.Factory.Factory.InstanceResolver.Get(Type type, String name, Func`2 constraint, ConstructorArgument[] constructorArguments, Boolean fallback) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\InstanceResolver.cs:line 75
       at Ninject.Extensions.Factory.StandardInstanceProvider.GetInstance(IInstanceResolver instanceResolver, MethodInfo methodInfo, Object[] arguments) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\StandardInstanceProvider.cs:line 78
       at Ninject.Extensions.Factory.FactoryInterceptor.Intercept(IInvocation invocation) in c:\Projects\Ninject\ninject.extensions.factory\src\Ninject.Extensions.Factory\Factory\FactoryInterceptor.cs:line 57
       at Castle.DynamicProxy.AbstractInvocation.Proceed()
       at Castle.Proxies.ICarFactoryProxy.CreateCar(String carType)
       at Ninject.Extensions.Conventions.Tests.NinjectFactoryTests.A_Car_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument() in C:\Programming\Ninject.Extensions.Conventions.Tests\NinjectFactoryTests.cs:line 33
  InnerException: 

我怎样才能得到这个测试通过?

[Fact]
public void A_Car_Factory_Creates_A_Car_Whose_Type_Name_Equals_Factory_Method_String_Argument()
{
    // auto-module loading is picking up my CarModule - otherwise, use:
    // using (StandardKernel kernel = new StandardKernel(new CarModule()))
    using (StandardKernel kernel = new StandardKernel())
    {
        // arrange
        string carTypeArgument = "Mercedes";
        ICarFactory factory = kernel.Get<ICarFactory>();

        // act
        var car = factory.CreateCar(carTypeArgument);

        // assert
        Assert.Equal(carTypeArgument, car.GetType().Name);
    }
}

下面的代码的其余部分,作为凝聚越好,这样你就不必参照原来的问题

public interface ICarFactory { ICar CreateCar(string carType); }

public interface ICar { void Drive(); void Stop(); }

public class Mercedes : ICar {
    public void Drive() { /* mercedes drives */ }
    public void Stop() { /* mercedes stops */ }
}

public class Ferrari : ICar {
    public void Drive() { /* ferrari drives */ }
    public void Stop() { /* ferrari stops */ }
}

public class UseFirstArgumentAsNameInstanceProvider : StandardInstanceProvider
{
    protected override string GetName(MethodInfo methodInfo, object[] arguments)
    {
        return (string) arguments[0];
    }

    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    {
        return base.GetConstructorArguments(methodInfo, arguments).Skip(1).ToArray();
    }
}

Answer 1:

看起来,你必须定义不同的约束力和提供的自定义实现IBindingGenerator这种情况

捆绑

所有的工作ICar将有自定义绑定

Kernel.Bind(scanner => scanner
                            .FromThisAssembly()
                            .SelectAllClasses()
                            .InheritedFrom<ICar>()
                            .BindWith(new BaseTypeBindingGenerator<ICar>()));

IBindingGenerator实施

在搜索界面的所有实现和类型名称将它们绑定

public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
    public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
    {
        if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
        {          
            yield return bindingRoot.Bind(typeof(InterfaceType))
                                    .To(type)
                                    .Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
        }
    }

PS:这里是一个全样本



文章来源: Ninject Conventions with Ninject Factory Extension To Bind Multiple Types To One Interface