Инжектиране на Enumerable, съдържащ всички регистрирани реализации на интерфейс

Предвид следния интерфейс:

public interface IMyProcessor
{
    void Process();
}

Бих искал да мога да регистрирам множество реализации и моят DI контейнер да инжектира изброени от тях в клас като този:

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();
        }
    }
 }

Възможно ли е това? Текущата ми реализация на MyProcessorLibrary търси всички IMyProcessor реализации статично, но бих предпочел да го направя чрез контейнер, ако мога. Използвам Unity, но съм любопитен дали други контейнери го поддържат.

Редактиране:

Благодаря за отговорите досега; за да бъде ясно, искам да инжектирам MyProcessorLibrary в друг клас и да го изградя като част от свързването на дърво от зависими обекти, напр.

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>();

person Steve Wilkes    schedule 07.03.2012    source източник
comment
възможен дубликат на Разрешаване на IEnumerable‹T› с Unity   -  person Mark Seemann    schedule 07.03.2012


Отговори (4)


Не мога да говоря за Unity, тъй като не го използвам, но определено е възможно с Ninject (вижте Multi Injection), който използвам.

person Trevor Pilley    schedule 07.03.2012
comment
Страхотно, всъщност точно това искам да направя... ако нищо не се появи за Unity, ще приема този отговор след малко. Благодаря! :) - person Steve Wilkes; 07.03.2012

Да, това е възможно. Всичко, от което се нуждаете, е да дадете имена на низове на типовете, които регистрирате в интерфейса. Register без име на низ все още присвоява име (доколкото си спомням, то е "По подразбиране") вътрешно, то се разрешава, когато извикате Resolve<T>, но не се разрешава когато се обадите на ResolveAll<T>. Така че може да се наложи да дадете някои имена на всичките си процесори.

Пример от msdn (адаптиран) :

// 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();
person oleksii    schedule 07.03.2012
comment
Благодаря много за това - мисля, че не бях достатъчно ясен във въпроса си. Актуализирах го. - person Steve Wilkes; 07.03.2012

Това е от документацията на Microsoft Unity 2.0. Проверете версията, която използвате. Не съм сигурен за други 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>();

РЕДАКТИРАНЕ:

// 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)
person Arseny    schedule 07.03.2012
comment
Благодаря много за това - мисля, че не бях достатъчно ясен във въпроса си. Актуализирах го. - person Steve Wilkes; 07.03.2012

Поддържа се напълно с MEF.

Ще трябва да експортирате всички класове, които имплементират този интерфейс, след което да използвате [ImportMany]

Пример:

public interface IMyProcessor { void Process(); }

[Export(typeof(IMyProcessor)]
public class FirstProc : IMyProcessor { ... }

[Export(typeof(IMyProcessor)]
public class SecondProc : IMyProcessor { ... }

[Export]
public class MyTest()
{
   [ImportMany]
   public IMyProcessor[] MyProcessors { get; set; }
}
person Louis Kottmann    schedule 07.03.2012