StructureMap:选择嵌套依赖项的具体类型

时间:2011-07-04 20:37:06

标签: c# dependency-injection structuremap constructor-injection

计算器:

public interface ICalculator
{
    int Calculate(int a, int b);
}

public class Calculator : ICalculator
{
    private readonly ICalculatorStrategy _calculatorStrategy;

    public Calculator(ICalculatorStrategy calculatorStrategy)
    {
        _calculatorStrategy = calculatorStrategy;
    }

    public int Calculate(int a, int b)
    {
        return _calculatorStrategy.Calculate(a, b);
    }
}

计算器stragies:

public interface ICalculatorStrategy
{
    int Calculate(int a, int b);
}

public class AdditionCalculator : ICalculatorStrategy
{
    public int Calculate(int a, int b)
    {
        return a + b;
    }
}

public class MultiplyCalculator : ICalculatorStrategy
{
    public int Calculate(int a, int b)
    {
        return a * b;
    }
}

计算器用法:

public class CalculatorUsageOne
{
    private readonly ICalculator _calculator;

    public CalculatorUsageOne(ICalculator calculator)
    {
        _calculator = calculator;
    }

    public void Process()
    {
        Console.WriteLine(_calculator.Calculate(6, 5));
    }
}

public class CalculatorUsageTwo
{
    private readonly ICalculator _calculator;

    public CalculatorUsageTwo(ICalculator calculator)
    {
        _calculator = calculator;
    }

    public void Process()
    {
        Console.WriteLine(_calculator.Calculate(6, 5));
    }
}

Structuremap Registry:

public class DependencyRegistry : Registry
{
    public DependencyRegistry()
    {
        For<ICalculatorStrategy>().Use<AdditionCalculator>().Named("Addition");
        For<ICalculatorStrategy>().Use<MultiplyCalculator>().Named("Multiply");
        For<ICalculator>().Use<Calculator.Calculator>();
    }
}

对于CalculatorUsageOne,我想添加数字(使用 AdditionCalculator )。 对于CalculatorUsageTwo我想要乘以数字(使用 MultiplyCalculator )。

如何使用StructureMap实现此目的?

2 个答案:

答案 0 :(得分:4)

试试这样:

For<CalculatorUsageOne>().Use<CalculatorUsageOne>()
    .Ctor<ICalculator>().Is<Calculator.Calculator>(
        x => x.Ctor<ICalculatorStrategy>().Is<AdditionCalculator>()
    );
For<CalculatorUsageTwo>().Use<CalculatorUsageTwo>()
    .Ctor<ICalculator>().Is<Calculator.Calculator>(
        x => x.Ctor<ICalculatorStrategy>().Is<MultiplyCalculator>()
    );

您可以根据需要嵌套对象图形配置。无论如何,我会考虑在这里使用泛型以更明确的方式显示依赖关系。

关于泛型的修改:

是否使用泛型是一个好主意,取决于您的方案。如果您没有有目的地指定CalculatorUsages的具体依赖关系,那么您的目标是使其与策略无关,那么您的解决方案似乎是最好的。

但是如果您只需要在“中间层”中共同实现Calculator,则可以在泛型参数中指定Calculator的依赖关系以使其显式化。也许这不是最好的用例,但它可以像这样:

public class CalculatorUsageOne
{
    public CalculatorUsageOne(ICalculator<AdditionCalculator> calculator)
    {
        // ...
    }
}

public class Calculator<T> where T : ICalculatorStrategy
{
    public Calculator(T strategy)
    {
        // ...
    }
}

并将其注册为:

For(typeof(ICalculator<>).Use(typeof(Calculator<>);

这将告诉StructureMap将请求的ICalculator的任何泛型参数传递给Calculatoropen generics),然后在构造函数中实例化策略对象。

或者,您可以使用marker interfaces代替泛型,但再一次,这一切都取决于您的特定情况,并且可能是从一开始就最简单的解决方案最适合。

答案 1 :(得分:1)

一种方法是使用With方法获取实例时定义依赖关系。

var additionStrategy = ObjectFactory
                            .GetNamedInstance<ICalculatorStrategy>("Addition");
var c1 = ObjectFactory.With(additionStrategy).GetInstance<CalculatorUsageOne>();

我能想到的另一种方法是在注册类型时将isntances作为构造函数参数提供。我明天可以提供一个例子。