fearofawhackplanet
fearofawhackplanet

Reputation: 53446

Injecting multiple matching classes with structuremap

interface IRecipe<T>
{
    ICollection<IIngredient<T>> Ingredients { get; set; }
    T Cook();
}

interface IIngredient<T> {}

public class Cheese : IIngredient<Pizza> {}
public class Tomato : IIngredient<Pizza> {}

public class Egg    : IIngredient<Omlette> {}

I want that when I request an instance of IRecipe<SomeType> StructureMap finds all implementations of IIngredient<SomeType> and registers them with Recipe somehow.

So e.g. if I request interface IRecipe<Pizza> I will get concrete instance of Recipe<Pizza> that has the correct ingredients.

Is there any way to achieve this?

Upvotes: 2

Views: 749

Answers (1)

qujck
qujck

Reputation: 14578

Yes this can be done with StructureMap.

I've made ICollection<IIngredient<T>> Ingredients readonly, added concrete implementations of Pizza and Omlette and extended Cheese and Tomato to be available for both Recipe's

public class Pizza { }
public class Omlette { }

public class Recipe<T> : IRecipe<T> where T : class, new()
{
    private readonly IEnumerable<IIngredient<T>> _ingredients;
    public Recipe(IEnumerable<IIngredient<T>> ingredients)
    {
        _ingredients = ingredients;
    }
    public ICollection<IIngredient<T>> Ingredients 
    { 
        get {  return _ingredients.ToList(); } 
    }
    public T Cook()
    {
        return new T();
    }
}

public interface IRecipe<T>
{
    ICollection<IIngredient<T>> Ingredients { get; }
    T Cook();
}

public interface IIngredient<T> { }
public class Cheese : IIngredient<Pizza>, IIngredient<Omlette> { }
public class Tomato : IIngredient<Pizza>, IIngredient<Omlette> { }
public class Egg : IIngredient<Omlette> { }

Here's the method for registration

public StructureMap.IContainer ConfigureStructureMap()
{
    StructureMap.IContainer structureMap;

    StructureMap.Configuration.DSL.Registry registry = 
        new StructureMap.Configuration.DSL.Registry();

    registry.Scan(scanner =>
    {
        scanner.TheCallingAssembly();
        scanner.ConnectImplementationsToTypesClosing(typeof(IIngredient<>));
    });

    structureMap = new StructureMap.Container(registry);

    structureMap.Configure(cfg => 
        cfg.For(typeof(IRecipe<>)).Use(typeof(Recipe<>)));

    return structureMap;
}

And two test methods

[Test]
public void StructureMapGetInstance_Pizza_ReturnsTwoIngredients()
{
    StructureMap.IContainer structureMap = ConfigureStructureMap();

    var pizza = structureMap.GetInstance<IRecipe<Pizza>>();

    Assert.That(pizza.Ingredients.Count, Is.EqualTo(2));
}

[Test]
public void StructureMapGetInstance_Omlette_ReturnsThreeIngredients()
{
    StructureMap.IContainer structureMap = ConfigureStructureMap();

    var omlette = structureMap.GetInstance<IRecipe<Omlette>>();

    Assert.That(omlette.Ingredients.Count, Is.EqualTo(3));
}

Upvotes: 4

Related Questions