【问题标题】:Ninject conditional bindingNinject 条件绑定
【发布时间】:2011-12-05 20:36:44
【问题描述】:

我正在家里使用 Ninject 进行一个简单的测试台项目,只是想看看我能用它做什么。作为一个起点,我正在为一些服务构建一个控制台运行器,它接受各种参数,并根据它输入的内容,使用为流式接口提供的相同方法来配置要运​​行的模型。

例如,假设我有一个详细程度开关,/o/o 可以传递为/o:quiet/o:normal/o:verbose。各种选项一目了然。

为了满足这个论点,我想附上ILogger 的各种实现 - quiet 获取一个仅打印关键消息的安静记录器,normal 获取一个普通记录器,verbose 获取一个打印所有内容的健谈记录器。

我想做的是模块中的一些东西,例如:

Bind<ILogger>().To<QuietLogger>().When(VerbosityParameter=="quiet");
Bind<ILogger>().To<VerboseLogger>().When(VerbosityParameter=="verbose");

...等等。

我看不出怎么做这样的事情;所有条件绑定似乎都依赖于注入目标的状态。那有什么意义呢?当消费类必须准确详细地指定确定它获得什么具体类型所需的所有条件时,它是否会破坏依赖注入的整个点?为什么我不能直接告诉 Ninject 我想要什么并得到它?

【问题讨论】:

  • 我意识到这个问题很古老,但我想我最近遇到了一个类似的问题,最后让 Ninject (在某种程度上)通过使用ToMethod 进行绑定来按照我想要的方式行事,并且然后将 Ninject 参数传递给内核的Get。这使我可以根据需要访问带有参数值的上下文。 stackoverflow.com/questions/22766200/…

标签: dependency-injection inversion-of-control ninject


【解决方案1】:

ctx 参数只是contextual binding 的一个输入 - 没有什么需要注意它(除非您需要与委托签名兼容)。

请记住RRR pattern,不要发疯。

你需要成为 IOW(在 V2 语法中这样做):

Bind<IWarrior>().To<Samurai>().When(_ => expression not involving context at all);

(其中_ 是一个穷人使用 F# 模式匹配语法忽略输入的 pidgin)

【讨论】:

  • 我错过了链接中的段落:"或者,您可以通过编程方式直接请求特定命名的服务实例(但要小心 - 直接这样做通常是Service Location antipattern) 通过执行: kernel.Get("Weak");" 这看起来更像我的想法 - 但为什么它是一个反模式?在什么可能的意义上,根据运行时参数从设计封装实例构造和检索的东西中检索不同的具体类型是一种反模式?
  • 如上所述,我更喜欢使用某种参数来解析 Configuration 实例,该参数指示 DI 框架应该做什么来创建配置。如果您无法在运行时根据用户输入进行更改,那还有什么意义?
  • 文档中的要点是,对 Get&lt;&gt; 的任何调用,除了组合根中的中间 R 位之外,a) 仅从 ctor args 无法辨别 b) 耦合到容器。首选方法是通过注入的自动生成的抽象工厂(请参阅stackoverflow.com/questions/4840157/…)或在您提供任何参数的组合根附近显式实现的抽象工厂来驱动此类创建,然后执行(可能命名的)Get 请求反对工厂中的内核,而不是您的服务类。
  • 我认为这是我最好的选择。工厂将是封装日志创建的传统方式,没有什么能阻止 Ninject 返回其中之一,但我希望使用 DI 框架可以最大限度地减少我必须编写/维护的工厂垃圾量。
【解决方案2】:

在这种特殊情况下,我不会替换记录器实例,而是配置您的日志框架以准确记录您想要的内容。

此外,When 条件不依赖于目标,您可以在其中放置任何类型的条件。例如

When(ctx => Configuration.Get("VerborsityLevel") == "quiet")

【讨论】:

  • 感谢您对此进行尝试。事后看来,我并没有那么清楚——在我看来,VerbosityLevel 不应该是配置实例的参数,因为我在帖子中提到的原因——这使得配置负责指定具体类型,打败了 DI 的观点。
  • 我的示例中的配置不是应用程序配置,而是配置值通过控制台参数传递。只需提供条件可以询问它们是否适用的东西。但正如我所说。在这种情况下,最好通过更改日志框架配置来更改详细程度。这也可以在代码中完成。
  • 这提出了同样的问题 - 如何我应该在运行时以对 DI 框架惯用的方式更改日志框架配置?
  • 行为应该被封装,运行时可配置的行为意味着多个服务实现一个契约。我们现在是说 DI 代码中服务实现者的选择应该在编译时配置吗?需要强调的是,我的代码中没有任何内容允许 DI 框架在必要时区分在编译时需要哪个实现。是否必然表明 DI 框架不能直接负责这些服务?
  • 暂时忽略我选择的示例是 Logger。事实上,我写了ILoggerDefaultLogger : ILogger 发布这个问题之后来探索给出的例子。有问题的服务可以是任何东西,因此请用日志服务的特定情况替换您认为适合由多个实施者配置的任何服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多