C#中的完全惰性流水线

4

我正在设计一个遵循责任链模式的处理程序管道。

管道处理程序具有以下接口:

public interface IPipelineHandler<TContext>
{
    Func<TContext, Task> Next { get; set; }
    Task HandleAsync(TContext context);
}

每个处理程序都对管道中下一个处理程序有一个引用。以下类用于构建管道:
public class PipelineBuilder<TContext>
{
    private readonly List<IPipelineHandler<TContext>> handlers
        = new List<IPipelineHandler<TContext>>();

    public PipelineBuilder<TContext> Register(IPipelineHandler<TContext> handler)
    {
        handlers.Add(handler);
        return this;
    }

    public Func<TContext, Task> Build()
    {
        IPipelineHandler<TContext> root = null;
        IPipelineHandler<TContext> prev = null;

        foreach (var handler in handlers)
        {
            if (root == null)
            {
                root = handler;
            }
            else
            {
                prev.Next = ctx => handler.HandleAsync(ctx);
            }

            prev = handler;
        }

        return root.HandleAsync;
    }
}

当前实现的缺陷在于,管道中的每个处理程序都是预先构建的。我想按需构建每个处理程序,因此不是将处理程序实例传递给构建函数,而是传递一个 Func<IPipelineHandler<TContext>>
为了使每个管道处理程序只在调用时创建,我需要对 Build() 进行哪些修改呢?
如果还不清楚,请注意:每个处理程序应该只在由管道中的前一个处理程序调用时创建,而不是在 Build() 方法期间创建。

1
你可以使用 DI服务定位器,而不是传递 IPipelineHandler 实例,你可以使用具体的 Type 进行注册,然后使用该 Type 按需解析实例。 - Luiso
传递Func并不难。我在如何惰性地构建管道方面感到困扰,即每个管道步骤都是按需创建的。 - Ben Foster
我猜你可能会喜欢HttpClient和ASP.NET Web API服务器的DelegatingHandler组合:https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Net.Http.Formatting/HttpClientFactory.cs#L57-L89 - tugberk
1个回答

1
最终解决方案非常简单。我创建了一个LazyPipelineHandler包装器,以便仍然可以构建管道,但在实际需要执行处理程序之前不会实例化包装的处理程序:
public class LazyPipelineHandler<TContext> : PipelineHandler<TContext>
{
    private readonly Lazy<IPipelineHandler<TContext>> innerHandler;

    public LazyPipelineHandler(Func<IPipelineHandler<TContext>> handlerFactory) 
    {
        this.innerHandler = new Lazy<IPipelineHandler<TContext>>(handlerFactory);
    }

    public override Task HandleAsync(TContext context, Func<TContext, Task> next) 
    {
        innerHandler.Value.Next = next;
        return innerHandler.Value.HandleAsync(context);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接