使用相同的接口调用多个类

我有一个像这样的界面

public interface IAddressProvider { string GetAddress(double lat, double long); } 

在我的消费类中,我想循环遍历具体的提供者,直到得到结果,如(简化):

 string address; address = _cachedAddressProvider.GetAddress(lat, long); if(address == null) address = _localDbAddressProvider.GetAddress(lat, long); if(address = null) address = _externalAddressProvider.GetAddress(lat, long); return address ?? "no address found"; 

然后我可以模拟每个提供程序进行unit testing,将null设置为返回值以适当地测试所有代码路径。

我如何将接口注入我的消费类(最好使用StructureMap),以便正确解析每个具体的实现?

您有多个地址提供程序的事实不是调用代码应该处理的事情。 因此,创建一个特定的提供者代理来处理这些多个提供者。

像这样。

 public interface IAddressProvider { string GetAddress(double lat, double long); } public class AddressProviderProxy: IAddressProvider { public AddressProviderProxy(IAddressProvider[] providers) { _providers = providers; // TODO: Add a NULL guard } private readonly IAddressProvider[] _providers; string IAddressProvider.GetAddress(double lat, double long) { foreach (var provider in _providers) { string address = provider.GetAddress(lat, long); if (address != null) return address; } return null; } } // Wire up using DI container.Register( () => new AddressProviderProxy( new IAddressProvider[3] { cachedAddressProvider, localDbAddressProvider, externalAddressProvider } ) ); // Use it IAddressProvider provider = ...from the container, injected.. string address = provider.GetAddress(lat, long) ?? "no address found"; 

你能不能只使用container.GetAllInstances ?,就像这样:

 var address = new List(); foreach (var provider in container.GetAllInstances()) { address.add(provider.GetAddress(lat, long)); } 

编辑:

我明白你的意思了。 如果您正在使用StructureMap 2.x,那么我建议您查看Conditionally子句。 但是, 在版本3中已删除此内容,以支持创建自己的构建器类,该类应负责返回正确的实例。

例如:

 public class AddressProviderBuilder : IInstanceBuilder { private readonly IContainer container; public AddressProviderBuilder(IContainer container) { this.container = container; } public IAddressProvider Build() { foreach (var provider in this.container.GetAllInstances()) { if (provider.GetAddress(lat, long) != null) { return provider; } } return null; } } 

我并不熟悉StructureMap,但据我所知,有两种解决方案。

1)命名实例 – 使用StructureMap将IAddressProvider 3个具体实现注册为命名实例,然后配置构造函数参数。

StructureMap命名实例配置: http : //docs.structuremap.net/InstanceExpression.htm#section14

在构造函数注入中使用命名参数: http : //lookonmyworks.co.uk/2011/10/04/using-named-instances-as-constructor-arguments/

2)更多接口 – 假设只有一些IAddressProvider实现而不是数百个,你可以创建一个实现IAddressProviderICachedAddressProviderILocalDbAddressProviderIExternalAddressProvider ,然后在消费类的构造函数中使用它们。

如果可能有更多具体的IAddressProvider实现,那么您可能想要查看抽象工厂的内容。