Calling multiple classes with the same interface

I have an interface like

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

In my consumption class, I want to go through specific suppliers until I get a result, for example (simplified):

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

I can then mock each provider for unit testing by setting null as the return value to properly test all code paths.

How would I introduce an interface into my consumer class (preferably using StructureMap) so that each particular implementation is correctly resolved?

+4
source share
3 answers

, , , . - .

.

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<IAddressProvider>(
    () => 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";
+2

StructureMap , , .

1) . 3 IAddressProvider StructureMap , .

StructureMap: http://docs.structuremap.net/InstanceExpression.htm#section14

: http://lookonmyworks.co.uk/2011/10/04/using-named-instances-as-constructor-arguments/

2) . , - IAddressProvider, , ICachedAddressProvider, ILocalDbAddressProvider IExternalAddressProvider, IAddressProvider, .

IAddressProvider, - Factory.

0

container.GetAllInstances?, :

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

Edit:

I understand what you mean now. If you are using StructureMap 2.x, I would recommend looking at the offer Conditionally. However, this was removed in version 3 in favor of creating our own builder class, which should be responsible for returning the correct instance.

For instance:

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<IAddressProvider>())
        {
            if (provider.GetAddress(lat, long) != null)
            {
                return provider;
            }
        }

        return null;
    }
}
0
source

Source: https://habr.com/ru/post/1570447/


All Articles