是的,您几乎需要按照您的描述进行操作,将附加数据从每个块传递到下一个块。
但是使用几个辅助方法,您可以使这变得更简单:
public static IPropagatorBlock<TInput, Tuple<TOutput, TInput>>
CreateExtendedSource<TInput, TOutput>(Func<TInput, TOutput> transform)
{
return new TransformBlock<TInput, Tuple<TOutput, TInput>>(
input => Tuple.Create(transform(input), input));
}
public static IPropagatorBlock<Tuple<TInput, TExtension>, Tuple<TOutput, TExtension>>
CreateExtendedTransform<TInput, TOutput, TExtension>(Func<TInput, TOutput> transform)
{
return new TransformBlock<Tuple<TInput, TExtension>, Tuple<TOutput, TExtension>>(
tuple => Tuple.Create(transform(tuple.Item1), tuple.Item2));
}
签名看起来令人生畏,但实际上并没有那么糟糕。
此外,您可能希望添加将选项传递给已创建块的重载,或采用异步委托的重载。
例如,如果您想使用单独的块对数字执行一些操作,同时传递原始数字,您可以执行以下操作:
var source = new BufferBlock<int>();
var divided = CreateExtendedSource<int, double>(i => i / 2.0);
var formatted = CreateExtendedTransform<double, string, int>(d => d.ToString("0.0"));
var writer = new ActionBlock<Tuple<string, int>>(tuple => Console.WriteLine(tuple));
source.LinkTo(divided);
divided.LinkTo(formatted);
formatted.LinkTo(writer);
for (int i = 0; i < 10; i++)
source.Post(i);
如您所见,您的 lambdas(除了最后一个)仅处理“当前”值(或int
,取决于管道的阶段),“原始”值(always )是自动传递的。在任何时候,您都可以使用使用普通构造函数创建的块来访问这两个值(如示例中的 final )。double
string
int
ActionBlock
(这BufferBlock
实际上不是必需的,但我添加它以更接近您的设计。)