Unity IoC регистрирует / разрешает два класса с интерфейсом и два типа - PullRequest
1 голос
/ 24 февраля 2012

У меня есть Calculator для отображения результатов в окне сообщений консоли или окна. Нет проблем, если у меня есть один тип для IOutputService. Теперь у меня есть два типа - ConsoleOutputService и MessageBoxOutputService.

Как я могу создать / зарегистрировать два калькулятора с разными типами в конструкторе и использовать калькулятор во время выполнения?


class Mockup
{
    void Bootstrapping()
    {
        UnityContainer container = new UnityContainer();

        container.RegisterType<IInputService, ConsoleInputService>();
        container.RegisterType<IOutputService, ConsoleOutputService>("Console");
        container.RegisterType<IOutputService, MessageBoxOutputService>("Window");

        // expect with ConsoleOutputService
        --> Pseudo code container.RegisterType<ICalculator, Calculator>("Cal1");
        // expect with MessageBoxOutputService
        --> Pseudo code container.RegisterType<ICalculator, Calculator>("Cal2");**
    }

    void RunConsole()
    {
        ICalculator lp = container.Resolve<ICalculator>("Cal1");
        lp.Run();
    }

    void RunWindow()
    {
        ICalculator lp = container.Resolve<ICalculator>("Cal2");
        lp.Run();
    }
}

public class Calculator : ICalculator
{
    public Calculator(IInputService inputService, IOutputService outputService)
    {
        InputService = inputService;
        OutputService = outputService;
    }
    public void Run()
    {            
    }
}       

1 Ответ

0 голосов
/ 25 февраля 2012

Прежде всего, вы можете пересмотреть свою архитектуру.Например, как насчет ожидания, пока вы не узнаете, к какому типу приложения вы принадлежите, прежде чем регистрировать выходной сервис.Тогда вы можете просто зарегистрировать тот, который вам нужен.Или вы могли бы добавить дополнительный уровень косвенности, попросив другую службу предоставить вам OutputService, и он мог бы знать, в каком режиме работает ваше приложение.

Но то, что вы просили сделать, возможно с единством.Есть два подхода.Во-первых, это использование InjectionConstructor с двумя ResolvedParameter s - это позволяет указать именованную службу вывода для использования.Тем не менее, он хрупок, поскольку, если вы реорганизуете конструктор Calculator, вы узнаете его только во время выполнения.

Так что лучшим подходом является InjectionFactory, где вы предоставляете ему Func, который создает ваш объект калькулятора.Этот Func может получить доступ к контейнеру, так что он может делать именованные разрешения.Вот проходной юнит-тест, который делает то, что вы хотите:

[Test]
public void NamedDependenciesTest()
{
    IUnityContainer container = new UnityContainer();
    container.RegisterType<IInputService, ConsoleInputService>();
    container.RegisterType<IOutputService, ConsoleOutputService>("Console");
    container.RegisterType<IOutputService, MessageBoxOutputService>("Window");

    container.RegisterType<ICalculator>("Cal1", new InjectionFactory((c) => new Calculator(c.Resolve<IInputService>(), c.Resolve<IOutputService>("Console"))));
    container.RegisterType<ICalculator>("Cal2", new InjectionFactory((c) => new Calculator(c.Resolve<IInputService>(), c.Resolve<IOutputService>("Window"))));

    // alternative setup with ResolvedParameter:
    //container.RegisterType<ICalculator, Calculator>("Cal1", new InjectionConstructor(new ResolvedParameter(typeof(IInputService)), new ResolvedParameter(typeof(IOutputService), "Console")));
    //container.RegisterType<ICalculator, Calculator>("Cal2", new InjectionConstructor(new ResolvedParameter(typeof(IInputService)), new ResolvedParameter(typeof(IOutputService), "Window")));

    var cal1 = container.Resolve<ICalculator>("Cal1");
    Assert.IsInstanceOf<ConsoleOutputService>(cal1.OutputService);
    var cal2 = container.Resolve<ICalculator>("Cal2");
    Assert.IsInstanceOf<MessageBoxOutputService>(cal2.OutputService);
}

interface IInputService { }
interface IOutputService { }
interface ICalculator { IOutputService OutputService { get; } }
class ConsoleInputService : IInputService { }
class ConsoleOutputService : IOutputService { }
class MessageBoxOutputService : IOutputService { }
class Calculator : ICalculator
{
    public Calculator(IInputService input, IOutputService output) { this.InputService = input; this.OutputService = output; }

    public IInputService InputService { get; private set; }
    public IOutputService OutputService { get; private set; }
}
...