Structuremap, конструктор, который принимает список плагинов - PullRequest
12 голосов
/ 17 сентября 2009

У меня есть такой интерфейс

public interface IWriter
{
  ...
}

и класс

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

Я хочу, чтобы Structuremap заполнял аргумент конструктора в 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 ..]]" (имя класса отредактировано)

Есть какой-нибудь трюк для этого автоматически? или мне придется сделать пользовательский метод фабрики?

Ответы [ 4 ]

18 голосов
/ 11 февраля 2010

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

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

StructureMap.ObjectFactory.Initialize(x =>
{
    x.Scan(scan =>
    {
        scan.TheCallingAssembly();
        scan.AddAllTypesOf<IWriter>();
    });
    x.ForRequestedType<IEnumerable<IWriter>>()
        .TheDefault.Is.ConstructedBy(x => ObjectFactory.GetAllInstances<IWriter>());
});
10 голосов
/ 17 сентября 2009

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

public WriterMerger(IWriter[] writers)

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

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

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

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

2 голосов
/ 17 сентября 2009

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

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

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

1 голос
/ 17 сентября 2009

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

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

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

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

...