Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting an Enumerable containing all registered Implementations of an Interface

Given the following interface:

public interface IMyProcessor
{
    void Process();
}

I'd like to be able to register multiple implementations and have my DI container inject an enumerable of them into a class like this:

public class MyProcessorLibrary
{
    private readonly IMyProcessor[] _processors;

    public MyProcessingThing(IMyProcessor[] processors)
    {
        this._processors = processors;
    }

    public void ProcessAll()
    {
        foreach (var processor in this._processors)
        {
            processor.Process();
        }
    }
 }

Is this possible? My current implementation of MyProcessorLibrary looks up all the IMyProcessor implementations statically, but I'd rather do it through a container if I can. I'm using Unity, but am curious if other containers support it.

Edit:

Thanks for the answers so far; to be clear I want to inject MyProcessorLibrary into another class, and have it built as part of the wiring up of a tree of dependent objects, e.g.

public class MyProcessorRepository
{
    public MyProcessorRepository(MyProcessorLibrary processorLibrary)
    {
    }
}

public class MyProcessorService
{
    public MyProcessorService(MyProcessorRepository processorRepository)
    {
    }
}

var container = new UnityContainer();
// Register a bunch of IMyProcessors...

var service = container.Resolve<MyProcessorService>();
like image 204
Steve Wilkes Avatar asked Mar 07 '12 10:03

Steve Wilkes


3 Answers

Yes, it is possible to do this. All you need, is to give string names to the types you are registering with the interface. Register without a string name still assignes a name (as far as I remember it is "Default") internally, it is resolved when you call Resolve<T>, but it is not resolved when you call ResolveAll<T>. So you may need to give all your processors some names.

A sample from msdn (adapted):

// Create container and register types using a name for each one
IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IMyProcessor, MyProcessorA>(); //default
myContainer.RegisterType<IMyProcessor, MyProcessorB>("MyProcessorB");
myContainer.RegisterType<IMyProcessor, MyProcessorC>("MyProcessorC");

// Retrieve a list of non-default types registered for IMyProcessor
// List will only contain the types MyProcessorB and MyProcessorC
IEnumerable<IMyProcessor> serviceList = myContainer.ResolveAll<IMyProcessor>();

//usage
var library = new  MyProcessorLibrary(serviceList);
library.ProcessAll();
like image 182
oleksii Avatar answered Oct 23 '22 20:10

oleksii


I can't speak for Unity as I don't use it but it is definitely possible with Ninject (see Multi Injection) which I do use.

like image 3
Trevor Pilley Avatar answered Oct 23 '22 20:10

Trevor Pilley


This is from Microsoft Unity 2.0 documentation. Check out the version you use. Not sure for others IoC.

// Create container and register types using a name for each one
IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IMyProcessor, MyProcessor1>();
myContainer.RegisterType<IMyProcessor, MyProcessor2>("number2");

// Retrieve a list of non-default types registered for IMyService
IEnumerable<IMyProcessor> processors = myContainer.ResolveAll<IMyService>();

EDIT:

// update MyProcessorLibrary with this property
[Dependency]
public IEnumerable<IMyProcessor> MyProcessingThing
{
 get { return _processors; }
 set { _processors = value; }
}

 //then inject the library class like this
 var lib = myContainer.Resolve<MyProcessorLibrary>();
 myProcessorRepository(lib)
like image 2
Arseny Avatar answered Oct 23 '22 20:10

Arseny