Внедрение перечислимого, содержащего все зарегистрированные реализации интерфейса - PullRequest
5 голосов
/ 07 марта 2012

Учитывая следующий интерфейс:

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, но мне любопытно, поддерживают ли другие контейнеры это.

Edit:

Спасибо за ответы до сих пор; чтобы быть понятным, я хочу внедрить 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>();

Ответы [ 4 ]

4 голосов
/ 07 марта 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();
1 голос
/ 07 марта 2012

Я не могу говорить за Unity, так как не пользуюсь им, но это определенно возможно с Ninject (см. Multi Injection ), который я использую.

1 голос
/ 07 марта 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)
0 голосов
/ 07 марта 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; }
}
...