【问题标题】:How to do proper contextual binding in Ninject?如何在 Ninject 中进行正确的上下文绑定?
【发布时间】:2019-02-15 21:40:42
【问题描述】:

到目前为止,我已经设法使用 Unity 和 Castle Windsor 轻松实现上下文绑定。意思是,给定一个接口的多个注册实现,我可以注册使用这些作为依赖项的客户端组件来选择一个特定的实现。但是,对于 Ninject,执行此操作的界面和我在以下位置找到的示例似乎没有相同的界面:

https://github.com/ninject/Ninject/wiki/Contextual-Binding#simple-constrained-resolution-named-bindings

统一示例:

给定接口、IFoo 和实现 Foo1、Foo2、Foo3。

container.RegisterType<IFoo , Foo1>("Foo1", new TransientLifetimeManager());
container.RegisterType<IFoo , Foo2>("Foo2", new TransientLifetimeManager());
container.RegisterType<IFoo , Foo3>("Foo3", new TransientLifetimeManager());
container.RegisterType<FooClient, FooClient>("FooClient1", new InjectionConstructor(new ResolvedParameter<IFoo>("Foo2")));
var fooClient = container.Resolve<FooClient>("FooClient1");

温莎城堡示例:

internal class FooInstaller: IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<IFoo>().Named("Foo1").ImplementedBy<Foo1>().LifeStyle.Transient);
        container.Register(Component.For<IFoo>().Named("Foo2").ImplementedBy<Foo2>().LifeStyle.Transient);
        container.Register(Component.For<IFoo>().Named("Foo3").ImplementedBy<Foo3>().LifeStyle.Transient);
        container.Register(Component.For<FooClient>().LifeStyle.Singleton.DependsOn(ServiceOverride.ForKey<IFoo>().Eq("Foo2")));
    }
}
var fooClient = container.Resolve<FooClient>();

Ninject(使用绑定元数据):

class FooClient{
    public FooClient(Named["Foo2"] IFoo fooDependency)
    {
    }
    ....
}

甚至在文档中承认它是一种反模式,直接使用服务定位器来请求特定的实现,而不是依赖于自动解析。

Unity & Castle Windsor 完全按照预期工作,fooClient 使用了 IFoo 的 Foo2 实现。它已自动解决。

关于 Ninject 方法,这是可行的,但这意味着它在更高级别组件的实现中是硬生生的,而且我违反了依赖倒置原则。 Unity/Windsor 方法的优点在于组合根(IOC 设置)是隔离点。

我错过了 Ninject API 上的某些东西可以让我保留 DIP?

【问题讨论】:

    标签: inversion-of-control ninject unity-container castle-windsor


    【解决方案1】:

    条件绑定

    你可以使用:

    Bind<FooClient>().ToSelf();
    Bind<IFoo>().To<Foo2>().WhenInjectedInto<FooClient>();
    

    绑定参数

    Bind<Foo2>().ToSelf();
    
    Bind<FooClient>().ToSelf()
        .WithConstructorArgument(typeof(IFoo)), ctx => ctx.Kernel.Get<Foo2>());
    

    注意:当然你也可以解析Kernel.Get&lt;IFoo&gt;("foo2")。 注意:键入“从内存”,可能无法编译,因为语法可能略有不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多