2013-03-11 3 views
3

Я новичок в autofac (используя 2.1.14.854), и им по-прежнему пытаются поставить мою голову вокруг, пытаясь понятьРегистрация компонента в autofac

У меня есть интерфейс и есть один или несколько реализаций этого интерфейс и реализация (и) должны быть запущены в определенной последовательности.

Например:

public IPipeline 
{ 
void execute(); 
} 


public MyPipeLine_1:IPipeline 
{ 
public void execute(){} 
} 

public MyPipeLine_2:IPipeline 
{ 
public void execute(){} 
} 

foreach(IPipeline pipeline in pipelines) 
      pipeline.execute(); 

Выполнение порядок IPipeline должно быть MyPipleLine_2, MyPipleLine_1 и т.д.

Я два вопроса 1) как регистрировать все компоненты, который реализует интерфейс IPipeLine в собрать и разместить их в списке 2) Могу ли я определить порядок выполнения этих компонентов при регистрации

Заранее благодарим.

ответ

2

[Быстрое примечание: вы используете действительно старую версию 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.

1

Я предлагаю вам использовать функцию Metadata. Это дает вам возможность определить заказ на этапе регистрации.

Вот пример:

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var builder = new ContainerBuilder(); 
     var s1 = "First"; 
     var s2 = "Second"; 
     var s3 = "Third"; 
     builder.RegisterInstance(s1).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 1)); 
     builder.RegisterInstance(s2).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 2)); 
     builder.RegisterInstance(s3).As<string>().WithMetadata<Order>(c => c.For(order => order.OrderNumber, 3)); 

     using (var container = builder.Build()) 
     { 
      var strings = container.Resolve<IEnumerable<Meta<string, Order>>>(); 
      foreach (var s in strings.OrderBy(meta => meta.Metadata.OrderNumber)) 
      { 
       Console.WriteLine(s.Value); 
      } 
     } 
     Console.ReadKey(); 
    } 

    public class Order 
    { 
     public int OrderNumber { get; set; } 
    } 
} 
Смежные вопросы