Внедрение 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 (см. < href="https://github.com/ninject/ninject/wiki/Multi-injection" rel="nofollow">Multi Injection), который я использую.

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

Да, это возможно. Все, что вам нужно, это дать строковые имена типам, которые вы регистрируете в интерфейсе. Register без строкового имени по-прежнему присваивает имя (насколько я помню, оно "Default") внутри, разрешается при вызове 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