使用Func的责任链

Ben*_*ter 5 c# chain-of-responsibility

我正在创建一个责任链管道,使用管道System.Func<T, T>中的每个函数保存对下一个函数的引用.

在构建管道时,我无法通过引用传递内部函数,因为它会因管道函数的重新分配而抛出StackOverflowException,例如:

Func<string, Func<string, string>, string> handler1 = (s, next) => {
    s = s.ToUpper();
    return next.Invoke(s);
};

Func<string, string> pipeline = s => s;
pipeline = s => handler1.Invoke(s, pipeline);

pipeline.Invoke("hello"); // StackOverFlowException
Run Code Online (Sandbox Code Playgroud)

我可以用一个闭包解决这个问题:

Func<string, Func<string, string>, string> handler1 = (s, next) => {
    s = s.ToUpper();
    return next.Invoke(s);
};

Func<Func<string, string>, Func<string, string>> closure = 
    next => s => handler1.Invoke(s, next);

Func<string, string> pipeline = s => s;
pipeline = closure.Invoke(pipeline);

pipeline.Invoke("hello");
Run Code Online (Sandbox Code Playgroud)

但是,我想知道是否有更有效的方法来构建这个函数链,也许使用表达式?

Eug*_*kov 2

那个怎么样?这样你就可以构建任意长度的链。

void Main()
{
    Func<string, string> f1 = x => x.Replace("*", string.Empty);
    Func<string, string> f2 = x => x.Replace("--", string.Empty);
    Func<string, string> f3 = x => x.ToUpper();

    //Func<string, string> pipeline = x => f3(f2(f1(x)));
    Func<string, string> pipeline = Pipeline(f1, f2, f3);

    pipeline.Invoke("te-*-st").Dump(); // prints "TEST"
}

Func<T, T> Pipeline<T>(params Func<T, T>[] functions)
{
    Func<T, T> resultFn = x => x;

    for (int i = 0; i < functions.Length; i++)
    {
        Func<T, T> f = functions[i];
        Func<T, T> fPrev = resultFn;
        resultFn = x => f(fPrev(x));
    }

    return resultFn;
}
Run Code Online (Sandbox Code Playgroud)