Подтвердить что ты не робот

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 всегда использовал Filelogger и McAfeeService для использования регистратора базы данных.

В приведенной выше программе я не могу связать NortonService с FileLogger.

Как это сделать?

4b9b3361

Ответ 1

Вышеупомянутые ответы приводят меня к встроенным зависимостям и функции переопределить службу

Вот регистрационный код:

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

Ответ 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>())
    );

Полная информация об этом подходе здесь. В исходном коде, предоставленном этим сообщением, я показываю два других способа достижения одного и того же результата.

Ответ 3

Мой ответ, возможно, не самый лучший, вы можете использовать метод именования для разрешения многопоточной реализации:

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

Метод Mine, возможно, не самый лучший, поскольку людям не нравится сервисный локатор для получения компонентов, вы можете использовать его как временное решение.

Ответ 4

Если вы хотите сделать это во время выполнения, это может быть достигнуто через IHandlerSelector. Напишите класс, реализующий IHandlerSelector. Он предоставляет метод SelectHandler, который позволит вам условно определить условие привязки во время выполнения. Обработчик в этом случае является компонентом в Виндзоре, который участвует в построении экземпляра. Подробнее см. здесь.