Fork me on GitHub

Working with Enumerable Types Edit on GitHub


While you can certainly use any IEnumerable type as a plugin type with your own explicit configuration, StructureMap has some built in support for these specific enumerable types:

  1. IEnumerable<T>
  2. IList<T>
  3. List<T>
  4. ICollection<T>
  5. T[]

Specifically, if you request one of these types either directly with GetInstance<IList<IWidget>>() or as a declared dependency in a constructor or setter (new WidgetUser(IList<IWidgets> widgets) for example) and you have no specific registration for the enumerable types, StructureMap has a built in policy to return all the registered instances of IWidget in the exact order that the registrations were made to StructureMap.

Note, if there are not any registrations for whatever T is, you'll get an empty enumeration.

Here's an acceptance test from the StructureMap codebase that demonstrates this:


[Fact]
public void collection_types_are_all_possible_by_default()
{
    // NOTE that we do NOT make any explicit registration of
    // IList<IWidget>, IEnumerable<IWidget>, ICollection<IWidget>, or IWidget[]
    var container = new Container(_ =>
    {
        _.For<IWidget>().Add<AWidget>();
        _.For<IWidget>().Add<BWidget>();
        _.For<IWidget>().Add<CWidget>();
    });

    // IList<T>
    container.GetInstance<IList<IWidget>>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));

    // ICollection<T>
    container.GetInstance<ICollection<IWidget>>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));

    // Array of T
    container.GetInstance<IWidget[]>()
        .Select(x => x.GetType())
        .ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
}

And another showing how you can override this behavior with explicit configuration:


[Fact]
public void override_enumeration_behavior()
{
    var container = new Container(_ =>
    {
        _.For<IWidget>().Add<AWidget>();
        _.For<IWidget>().Add<BWidget>();
        _.For<IWidget>().Add<CWidget>();

        // Explicit registration should have precedence over the default
        // behavior
        _.For<IWidget[]>().Use(new IWidget[] { new DefaultWidget() });
    });

    container.GetInstance<IWidget[]>()
        .Single().ShouldBeOfType<DefaultWidget>();
}

Sample Usage: Validation Rules

One of the ways that I have used the built in IEnumerable handling is for extensible validation rules. Say that we are building a system to process IWidget objects. As part of processing a widget, we first need to validate that widget with a series of rules that we might model with the IWidgetValidator interface shown below and used within the main WidgetProcessor class:


public interface IWidgetValidator
{
    IEnumerable<string> Validate(IWidget widget);
}

public class WidgetProcessor
{
    private readonly IEnumerable<IWidgetValidator> _validators;

    public WidgetProcessor(IEnumerable<IWidgetValidator> validators)
    {
        _validators = validators;
    }

    public void Process(IWidget widget)
    {
        var validationMessages = _validators.SelectMany(x => x.Validate(widget))
            .ToArray();

        if (validationMessages.Any())
        {
            // don't process the widget
        }
    }
}

We could simply configure all of the IWidgetValidator rules in one place with an explicit registration of IEnumerable<IWidgetValidator>, but what if we need to have an extensibility to add more validation rules later? What if we want to add these additional rules in addon packages? Or we just don't want to continuously break into the centralized Registry class every single time we add a new validation rule?

By relying on StructureMap's IEnumerable behavior, we're able to split our IWidgetValidatior registration across multiple Registry classes and that's not infrequently useful to do.