MEF Gems 2 of many: Collections

So in the previous gem I went over the differences between import and import many. Now let’s consider the different ways to import many dependencies.

Check this piece of code:

     [InheritedExport]
    abstract class Foo { }

    class Foo1 : Foo { }
    class Foo2 : Foo { }
    class Foo3 : Foo { }

So here we have a single contract and three exports just to make volume and test the collection imports. The first way you’d think of importing them would be using IEnumerable<Foo>:

     [Export]
    class ImportsOfCollections
    {
        [ImportMany]
        public IEnumerable<Foo> Foos { get; set; }
    }

And this works. Note that MEF will instantiate an implementation of IEnumerable<T> and set the property. This is the default behavior for this type.

Another way you may consider is a standard array:

     [Export]
    class ImportsOfCollections
    {
        [ImportMany]
        public Foo[] FoosArray { get; set; }
    }

This option also leaves to MEF the instantiation of the array type.

Now, a different way would be using ICollection<T>:

     [Export]
    class ImportsOfCollections
    {
        [ImportMany]
        public ICollection<Foo> FoosColl { get; set; }
    }

In this case, if you run this code you’ll get an error. That’s because MEF doesn’t know which implementation of ICollection you want. It expects you to take care of that. Easy fix:

     [Export]
    class ImportsOfCollections
    {
        public ImportsOfCollections()
        {
            FoosColl = new List<Foo>();
        }

        [ImportMany]
        public ICollection<Foo> FoosColl { get; set; }
    }

And now it will work as expected. This allows you to use anything that implements ICollection<T> including ObservableCollection<T>.

Behavior on recomposition

What would happen to my collections if a recomposition is triggered? It depends.

If MEF owns the collection instance, it would supply your components with new instances. Otherwise, it will call .Clear and .Add as many time as needed to repopulate the collection.

In other words, for IEnumerable<> and Array, MEF will supply a new instance to the property. For ICollection<> implementations, it will call .Clear and .Add.