我是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接口的所有组件并将它们放在List中 2)我可以在注册时定义这些组件的执行顺序
提前致谢。
答案 0 :(得分: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 :(得分: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; }
}
}