Castle Windsor – implémentation multiple d’une interface

Lors de l’enregistrement de composants dans Castle Windsor, comment lier une implémentation spécifique d’une interface à un composant dépendant de cette interface. Je sais à l’avance quelle implémentation doit être utilisée par le composant.

Par exemple, j’ai créé un exemple d’application de console basé sur le code de plusieurs blogs et tutoriels.

Voici le code.

public interface IReport { void LogReport(); } public interface ILogger { ssortingng Log(); } public class FileLogger : ILogger { public ssortingng Log() { return "Logged data to a file"; } } public class DatabaseLogger : ILogger { public ssortingng 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() { ssortingng 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() { ssortingng getLogResult = this._logger.Log(); Console.WriteLine("Norton Scan has " + getLogResult); } } class Program { private static IWindsorContainer container; static void Main(ssortingng[] args) { // Register components container = new WindsorContainer(); container.Register(Component.For().ImplementedBy()); container.Register(Component.For().ImplementedBy()); IReport service = container.Resolve(); service.LogReport(); Console.ReadLine(); } } 

J’aimerais que NortonService utilise toujours un Filelogger et McAfeeService utilise un enregistreur de firebase database.

Dans le programme ci-dessus, je ne parviens pas à associer NortonService à FileLogger.

Comment faire?

Les réponses ci-dessus me mènent aux dépendances en ligne et au remplacement du service de fonctionnalité

Voici le code d’enregistrement:

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

Sortie:

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

J’ai eu un problème très semblable à celui-ci, deux implémentation d’une interface et deux implémentation d’une autre interface. Je voulais forcer l’utilisation d’implémentations particulières de ces interfaces.

Ma structure de classe ressemblait à ceci –

entrez la description de l'image ici

J’ai regardé la convention de nommage, mais je ne l’ai pas vraiment aimé. Au lieu de cela, j’ai utilisé ce qui suit –

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

Les informations complètes sur cette approche sont ici . Dans le code source fourni avec cet article, je montre deux autres moyens d’obtenir le même résultat.

Ma réponse n’est peut-être pas la meilleure, vous pouvez utiliser une méthode de dénomination pour résoudre une implémentation multiple:

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

Dans vos fonctions d’appel, vous devez le résoudre par nom: –

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

La méthode des mines n’est peut-être pas la meilleure, car les gens n’aiment pas que le service de localisation obtienne les composants, vous pouvez l’utiliser comme solution temporaire.

Si vous voulez le faire au moment de l’exécution, cela peut être réalisé via IHandlerSelector. Ecrivez une classe qui implémente IHandlerSelector. Il fournit une méthode SelectHandler qui vous permettra de définir la condition de liaison conditionnelle au moment de l’exécution. Dans ce cas, un gestionnaire est un composant de Windsor qui participe à la construction d’instances. Reportez-vous ici pour plus de détails.