Unity IoC使用接口和两种类型注册/解析两个类

时间:2012-02-24 16:35:06

标签: c# inversion-of-control unity-container

我有Calculator在控制台或窗口消息框上显示结果。 如果IOutputService有一种类型,则没有问题。 现在,我有两种类型 - ConsoleOutputServiceMessageBoxOutputService

如何在构造函数中创建/注册两个具有不同类型的计算器,并在运行时使用计算器?


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 :(得分:0)

首先,您可能想重新考虑您的架构。例如,如何在注册输出服务之前等到知道自己的应用程序类型。然后你可以注册你需要的那个。或者你可以添加一个额外的间接层,要求另一个服务来获取OutputService,并且可以知道你的应用运行的模式。

但你要求的是团结一致。有两种方法。首先是使用InjectionConstructor和两个ResolvedParameter - 这允许您指定要使用的命名输出服务。但是,它很脆弱,因为如果你重构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; }
}