2013-08-02 55 views
19

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<IReport>().ImplementedBy<NortonService>()); 
     container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>()); 

     IReport service = container.Resolve<IReport>(); 
     service.LogReport(); 

     Console.ReadLine(); 
    } 
} 

NortonServiceはFile LoggerとMcAfeeServiceを使用してデータベース・ロガーを使用したいと考えています。

上記のプログラムでは、NortonServiceをFileLoggerにバインドできません。

どうすればよいですか?

答えて

2
私の答えは、そうでないかもしれない最高の1、あなたはマルチ実装解決する方法を命名使用することができます

:あなたの呼び出し元の関数で

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)); 

私の方法はおそらく人々がサービスロケータがコンポーネントを取得するのが好きではないので、あなたは一時的な解決策としてこれを使用することができます最高のものではありません。

20

上記の答えは、依存関係をインライン化するために私をリードし、ここで機能service override

は、登録コードは次のとおりです。

container.Register(Component.For<IReport>().ImplementedBy<NortonService>().Named("nortonService")); 

container.Register(Component.For<ILogger>().ImplementedBy<FileLogger>()); 
container.Register(Component.For<ILogger>().ImplementedBy<DatabaseLogger>()); 

container.Register(
    Component.For<IReport>().ImplementedBy<McAfeeService>().Named("mcafeeService") 
     .DependsOn(Dependency.OnComponent<ILogger, DatabaseLogger>()) 
); 

IReport mcafeescan = container.Resolve<IReport>("mcafeeService"); 
mcafeescan.LogReport(); 

IReport nortonscan = container.Resolve<IReport>("nortonService"); 
nortonscan.LogReport(); 

出力:

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

私は非常にこのような問題を抱えていました、 1つのインターフェイスの2つの実装と別のインターフェイスの2つの実装。私はこれらのインターフェイスの特定の実装を強制的に使用したいと思っていました。

私のクラス構造はこのように見えた -

enter image description here

私が命名規則に見えたが、実際にそれを好きではなかったです。代わりに私は以下を使用しました -

public void Install(IWindsorContainer container, IConfigurationStore store) 
    { 
    container.Register(
     Component.For<IMessageLoader>().ImplementedBy<MessageLoaderDatabase>() 
     ,Component.For<IMessageLoader>().ImplementedBy<MessageLoaderFile>() 

     ,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceDatabase>() 
      .DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderDatabase>()) 

     ,Component.For<IMessageOfTheDayService>().ImplementedBy<MessageOfTheDayServiceFile>() 
      .DependsOn(Dependency.OnComponent<IMessageLoader, MessageLoaderFile>()) 

     ,Component.For<MessageOfTheDayController>().LifestyleTransient() 
      .DependsOn(Dependency.OnComponent<IMessageOfTheDayService, MessageOfTheDayServiceFile>()) 
    ); 

このアプローチに関する完全な情報はhereです。この記事で提供されているソースコードには、同じ結果を達成するための2つの方法があります。

2

実行時に実行したい場合は、これはIHandlerSelectorで確認できます。 IHandlerSelectorを実装するクラスを記述します。実行時に条件付きでバインドする条件を定義できるメソッドSelectHandlerを提供します。この場合のハンドラは、インスタンス構築に参加するWindsorのコンポーネントです。詳細はhereを参照してください。

関連する問題