Подтвердить что ты не робот

Structuremap, конструктор, который принимает список плагинов

Я получил такой интерфейс

public interface IWriter
{
  ...
}

и класс

public class WriterMerger
{
  public WriterMerger(IEnumerable<IWriter> writers)
  ...
}

Я хочу, чтобы structmap заполнил аргумент конструктора в WriterMerger со всеми зарегистрированными IWriter. Я зарегистрировал разных авторов с помощью

StructureMap.ObjectFactory.Initialize(x =>
{
  x.ForRequestedType<IWriter>().AddConcreteType<MemoryWriter>();
  x.ForRequestedType<IWriter>().AddConcreteType<FlatFileWriter>();
  x.ForRequestedType<IWriter>().AddConcreteType<DbWriter>();
}

однако вызов

ObjectFactory.CreateInstance<WriterMerger>();

Возвращает исключение "Нет экземпляра по умолчанию, определенного для PluginFamily System.Collections.Generic.IEnumerable`1 [[IWriter..]]" (имя класса отредактировано)

Любой трюк для этого автоматически? или мне придется создать собственный factory метод?

4b9b3361

Ответ 1

Если вы хотите, чтобы все конкретные экземпляры типа были введены, вы ДОЛЖНЫ объявить этот параметр как массив. Вы можете исправить свою проблему, изменив свой конструктор на:

public WriterMerger(IWriter[] writers)

Помните, что инструменты очистки кода, такие как ReSharper, могут выделять массив в вашем конструкторе и предлагать вам заменить его на IEnumerable, если это все, что требуется вашему WriterMerger. Однако эти инструменты не знают о требовании StructureMap для использования массива, поэтому вы должны игнорировать его.

Вам также может быть интересно узнать, что вы можете автоматически регистрировать все ваши IWriters, а не явно перечислять их. Просто измените конфигурацию контейнера на:

StructureMap.ObjectFactory.Initialize(x =>
{
    x.Scan(scan =>
    {
        scan.TheCallingAssembly();
        scan.AddAllTypesOf<IWriter>();
    });
});

Существует несколько различных вариантов сканирования, которые позволяют сканировать различные сборки, исключать определенные типы и т.д.

Ответ 2

На самом деле это можно сделать без изменения конструктора

Измените конфигурацию вашего контейнера на:

StructureMap.ObjectFactory.Initialize(x =>
{
    x.Scan(scan =>
    {
        scan.TheCallingAssembly();
        scan.AddAllTypesOf<IWriter>();
    });
    x.ForRequestedType<IEnumerable<IWriter>>()
        .TheDefault.Is.ConstructedBy(x => ObjectFactory.GetAllInstances<IWriter>());
});

Ответ 3

Я продублировал вашу проблему, и я считаю, что ваш код будет работать, если вы измените класс потребления IWriter на наличие ctor, который принимает массив IWriter.

public class WriterMerger {  public WriterMerger(IWriter[] writers) }

Джош прав, рекомендуя лучший способ зарегистрировать все типы IWriter с StructureMap. Сканеры FTW.

Ответ 4

Я думаю, что это говорит вам, что вам нужно определить один из этих IWriters как значение по умолчанию. Представьте, что у другого класса был следующий конструктор:

public class Test{
  public Test(IWriter writer){}
}

Без IWriter по умолчанию он не знает, какой писатель должен назначить. Таким образом, вам, вероятно, нужно сказать, что является по умолчанию, даже если вы никогда его не используете. Посмотреть это сообщение:

В чем разница между AddConcreteType и TheDefaultIsConcreteType в StructureMap?