Castle Windsor – 多个接口实现

在Castle Windsor中注册组件时,我们如何将接口的特定实现绑定到依赖于该接口的组件。 我事先知道组件需要使用哪种实现方式。

例如,我基于来自几个博客和教程的代码创建了一个示例控制台应用程序。

以下是代码。

public interface IReport { void LogReport(); } public interface ILogger { string Log(); } public class FileLogger : ILogger { public string Log() { return "Logged data to a file"; } } public class DatabaseLogger : ILogger { public string Log() { return "Logged data to a database"; } } public class McAfeeService : IReport { private readonly ILogger _logger; public McAfeeService(ILogger logger) { this._logger = logger; } public void LogReport() { string getLogResult = this._logger.Log(); Console.WriteLine("McAfee Scan has " + getLogResult); } } public class NortonService : IReport { private readonly ILogger _logger; public NortonService(ILogger logger) { this._logger = logger; } public void LogReport() { string getLogResult = this._logger.Log(); Console.WriteLine("Norton Scan has " + getLogResult); } } class Program { private static IWindsorContainer container; static void Main(string[] args) { // Register components container = new WindsorContainer(); container.Register(Component.For().ImplementedBy()); container.Register(Component.For().ImplementedBy()); IReport service = container.Resolve(); service.LogReport(); Console.ReadLine(); } } 

我希望NortonService始终使用Filelogger和McAfeeService来使用数据库记录器。

在上面的程序中,我无法将NortonService绑定到FileLogger。

怎么做?

上面的答案引导我进行内联依赖和function服务覆盖

这是注册码:

 container.Register(Component.For().ImplementedBy().Named("nortonService")); container.Register(Component.For().ImplementedBy()); container.Register(Component.For().ImplementedBy()); container.Register( Component.For().ImplementedBy().Named("mcafeeService") .DependsOn(Dependency.OnComponent()) ); IReport mcafeescan = container.Resolve("mcafeeService"); mcafeescan.LogReport(); IReport nortonscan = container.Resolve("nortonService"); nortonscan.LogReport(); 

输出:

 McAfee Scan has Logged data to a database Norton Scan has Logged data to a file 

我有一个非常类似的问题,一个接口的两个实现和另一个接口的两个实现。 我想强制使用这些接口的特定实现。

我的class级结构看起来像这样 –

在此处输入图像描述

我查看了命名约定,但并不喜欢它。 相反,我使用以下 –

  public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Component.For().ImplementedBy() ,Component.For().ImplementedBy() ,Component.For().ImplementedBy() .DependsOn(Dependency.OnComponent()) ,Component.For().ImplementedBy() .DependsOn(Dependency.OnComponent()) ,Component.For().LifestyleTransient() .DependsOn(Dependency.OnComponent()) ); 

关于这种方法的完整信息在这里 。 在该post提供的源代码中,我展示了另外两种实现相同结果的方法。

我的答案可能不是最好的,您可以使用命名方法来解决多个实现:

  container.Register(Component.For(typeof(ILogger)) .ImplementedBy(typeof(FileLogger)) .Named("FileLoggerIoC") .LifestylePerWebRequest() , Component.For(typeof(ILogger)) .ImplementedBy(typeof(DatabaseLogger)) .Named("DatabaseLoggerIoC") .LifestylePerWebRequest()); 

在您的调用函数中,您需要按名称解析它: –

 var fileLog = container.Resolve("FileLoggerIoC", typeof(ILogger)); var DbLog = container.Resolve("DatabaseLoggerIoC", typeof(ILogger)); 

我的方法可能不是最好的,因为人们不喜欢服务定位器来获取组件,你可以使用它作为临时解决方案。

如果你想在运行时这样做,可以通过IHandlerSelector实现。 编写一个实现IHandlerSelector的类。 它提供了一个方法SelectHandler,它允许您在运行时有条件地定义绑定条件。 在这种情况下,处理程序是Windsor中参与实例构造的组件。 请参阅此处了解更多详情。