[Быстрое примечание: вы используете действительно старую версию Autofac. Возможно, вам придется обновить, чтобы получить функции, о которых я говорю.]
Первая часть проста - Autofac implicitly supports IEnumerable<T>
. Просто зарегистрировать все типы и разрешения:
var builder = new ContainerBuilder();
builder.RegisterType<MyPipeLine_1>().As<IPipeline>();
builder.RegisterType<MyPipeLine_2>().As<IPipeline>();
var container = builder.Build();
var containsAllPipelineComponents = container.Resolve<IEnumerable<IPipeline>>();
Было бы лучше, если вы можете взять его в качестве IEnumerable<T>
, а не список, но если вы должны иметь список, вы можете добавить регистрацию для него:
builder
.Register(c => new List<IPipeline>(c.Resolve<IEnumerable<IPipeline>>()))
.As<IList<IPipeline>>();
Вторая часть не так проста. Autofac не обязательно гарантирует порядок элементов в списке. Если вам нужно их заказать, вам нужно будет указать на них какие-то метаданные упорядочения - атрибуты, свойства, то, что вы можете использовать для заказа конвейера после факта.
В качестве альтернативы, если ваш конвейер имеет «этапы» или «события», где применимы разные компоненты, посмотрите на конструкцию вашего конвейера и на другой интерфейс трубопровода на одно событие. Внутри события не должно иметь значения, в каком порядке выполняется каждый элемент. (Это похоже на то, как обработчики событий в .NET работают сейчас. Вы хотите подражать этому поведению - разные события для разных этапов в течение всего жизненного цикла, но внутри каждый конкретный этап порядок выполнения обработчиков не имеет значения)
примером может выглядеть следующим образом:.
public interface IFirstStage
{
void Execute();
}
public interface ISecondStage
{
void Execute();
}
public interface IThirdStage
{
void Execute();
}
public class PipelineExecutor
{
public IEnumerable<IFirstStage> FirstHandlers { get; private set; }
public IEnumerable<ISecondStage> SecondHandlers { get; private set; }
public IEnumerable<IThirdStage> ThirdHandlers { get; private set; }
public PipelineExecutor(
IEnumerable<IFirstStage> first,
IEnumerable<ISecondStage> second,
IEnumerable<IThirdStage> third)
{
this.FirstHandlers = first;
this.SecondHandlers = second;
this.ThirdHandlers = third;
}
public void ExecutePipeline()
{
this.ExecuteFirst();
this.ExecuteSecond();
this.ExecuteThird();
}
public void ExecuteFirst()
{
foreach(var handler in this.FirstHandlers)
{
handler.Execute();
}
}
// ExecuteSecond and ExecuteThird look just
// like ExecuteFirst, but with the appropriate
// set of handlers.
}
Затем, когда вы регистрируетесь обработчики это просто:
var builder = new ContainerBuilder();
builder.RegisterType<SomeHandler>().As<IFirstStage>();
builder.RegisterType<OtherHandler>().As<IFirstStage>();
builder.RegisterType<AnotherHandler>().As<ISecondStage>();
// You can have any number of handlers for any stage in the pipeline.
// When you're done, make sure you register the executor, too:
builder.RegisterType<PipelineExecutor>();
И когда вам нужно запустить конвейер, разрешить и запустить.
var executor = container.Resolve<PipelineExecutor>();
executor.ExecutePipeline();
Это похоже на обработчики событий, но не на использование делегатов. У вас есть фиксированный порядок «событий» трубопровода или «этапов», но обработчики внутри каждого этапа не гарантированы.
Если вам нужно изменить конвейер, чтобы иметь больше этапов, да, вам нужно будет изменить код. Также как если бы у вас было новое событие, которое вы хотели разоблачить. Однако для добавления, удаления или изменения обработчиков вы просто изменяете регистрацию Autofac.