Зависимость конструктора массива от StructureMap

В моем TaskRegistry я определил несколько ITask типов бетонов:

public class TaskResigstry : Registry
{
    public TaskResigstry()
    {
        ForRequestedType<IBootstrapperTask>().TheDefaultIsConcreteType<StartTasks>();

        ForRequestedType<ITask>().TheDefaultIsConcreteType<FirstTask>();
        ForRequestedType<ITask>().AddConcreteType<SecondTask>();
        ForRequestedType<ITask>().AddConcreteType<ThirdTask>();
    }
}

И мой StartTasks

public class StartTasks : IBootstrapperTask
{
    public StartTasks(ITask[] tasks)
    {
        foreach(var task in tasks)
        {
            task.Run();
        }
    }
}

Как я могу ввести параметр конструктора ITask[] с помощью StructureMap?

Спасибо.


person Yoann. B    schedule 01.11.2009    source источник


Ответы (3)


Если вы хотите ввести массив, в свободном интерфейсе есть метод для этого ...

ForRequestedType<IBootStrapperTask>().TheDefault.Is.OfConcreteType<StartTasks>()
     .TheArrayOf<ITask>().Contains(
            y => {
                y.OfConcreteType<Task1>();
                y.OfConcreteType<Task2>();
                y.OfConcreteType<Task3>();
            });

Если вы хотите пойти по пути принятия IEnumerable<T> в вашем конструкторе, насколько я могу видеть, все начинает становиться немного сложнее. Вы можете указать и построить аргумент конструктора следующим образом: -

ForRequestedType<IBootStrapperTask>().TheDefault.Is.OfConcreteType<StartTasks>()
            .CtorDependency<IEnumerable<ITask>>().Is(i => {
                i.Is.ConstructedBy(c => {
                    return new List<ITask> { 
                           c.GetInstance<Task1>(), 
                           c.GetInstance<Task2>(), 
                           c.GetInstance<Task3>()
                    };
                });
            });

Если вам нужны все зарегистрированные типы, вы можете создать собственный IBuildInterceptor, который обращается ко всем зарегистрированным типам через метод CreateInstanceArray в BuildSession, но у меня такое чувство, что я могу пойти по неправильному пути.

Я хотел бы, чтобы меня поправили, что это намного проще :).

person John Foster    schedule 02.11.2009
comment
Если вы хотите использовать IEnumerable ‹T›, но не хотите указывать каждый экземпляр, вы можете сделать что-то вроде: .CtorDependency ‹IEnumerable ‹ITask›› (). Is (instance = ›instance .ConstructedBy (ctx =› ctx.GetInstance ‹IContainer› () .GetAllInstances ‹ITask› ())); - person Joshua Flanagan; 04.11.2009
comment
Я думал, что иду не по той дороге. Забыл, что я могу добраться до контейнера, ура! - person John Foster; 04.11.2009

Вам не нужно больше ничего делать. Просто запросите экземпляр IBootstrapperTask, и все IT-задачи будут внедрены автоматически.

var container = new Container(x => x.AddRegistry<TaskResigstry>());
var bootstrapper = container.GetInstance<IBootstrapperTask>();

Примечание. StructureMap распознает массивы только для внедрения нескольких экземпляров - не изменяйте конструктор, чтобы он принимал IEnumerable или строго типизированную коллекцию.

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

public class TaskResigstry : Registry
{
    public TaskResigstry()
    {
        ForRequestedType<IBootstrapperTask>().TheDefaultIsConcreteType<StartTasks>();

        Scan(x =>
        {
            x.TheCallingAssembly();
            x.AddAllTypesOf<ITask>();
        });
    }
}
person Joshua Flanagan    schedule 03.11.2009

Принятый ответ хорош, но синтаксис устарел. Вот новый синтаксис, который делает то же самое:

this.For<IBootStrapperTask>().Use<StartTasks>()
    .EnumerableOf<ITask>().Contains(x =>
    {
        x.Type<Task1>();
        x.Type<Task2>();
        x.Type<Task3>();
    });

StructureMap великолепен, но меня часто расстраивает отсутствие примеров, в которых используется самый современный синтаксис.

person NightOwl888    schedule 10.03.2013