3

我是 autofac 的新手(使用 2.1.14.854),我仍在努力尝试理解

我有一个接口,并且该接口有一个或多个实现,并且应按特定顺序触发实现。

例如:

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)我可以在注册时定义这些组件的执行顺序吗

提前致谢。

4

2 回答 2

2

[快速说明:您使用的是非常旧的 Autofac 版本。您可能需要更新以获得我正在谈论的功能。]

第一部分很简单——Autofac 隐式支持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 注册。

于 2013-03-11T15:11:27.103 回答
1

我建议您使用元数据功能。它使您可以在注册阶段定义订单。

这是一个例子:

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; }
    }
}
于 2013-03-14T19:39:31.717 回答