22

TPL Dataflow提供了一个TransformBlock用于转换输入的方法,例如:

var tb = new TransformBlock<int, int>(i => i * 2);

是否可以不输出某些输入,例如,如果输入未通过某些验证测试?

var tb = new TransformBlock<InputType, OutputType>(i =>
{
    if (!ValidateInput(i))
    {
        // Do something to not output anything for this input
    }
    // Normal output
}

如果这不可能,那么实现这一目标的最佳模式是什么?
像下面这样的东西?

BufferBlock<OutputType> output = new BufferBlock<OutputType>();

var ab = new ActionBlock<InputType>(i =>
{
    if (ValidateInput(i)) 
    {
        output.Post(MyTransform(i));
    }
}
4

3 回答 3

26

关于如何执行此操作有多种选择:

  1. 按照 Jon 的建议使用TransformManyBlock并返回包含 1 或 0 个项目的集合。
  2. TransformBlock与一些表示“无值”的特殊值一起使用(例如null),然后使用LinkTo()with 过滤器将其删除。您还必须在没有过滤器的情况下链接TransformBlock到空块 ( DataflowBlock.NullTarget<T>()),以排出特殊值。
  3. 我会认为这是一种 hack,但您也可以使用Task基于 - 的构造函数TransformBlockTask.FromResult()当您想要返回某些东西时使用,而当您不想返回时使用null。例如:

    new TransformBlock<int, int>(i => i % 2 == 0 ? Task.FromResult(i * 2) : null)
    
于 2012-10-31T20:47:56.890 回答
12

我自己没有使用过 DataFlow,但我认为您可以使用 a TransformManyBlock,并让每个步骤返回一个空集合或单个项目。

var tmb = new TransformManyBlock<InputType, OutputType>(i =>
{
    if (!ValidateInput(i))
    {
        return Enumerable.Empty<OutputType>();
    }
    ...
    // Or return new[] { outputValue };
    return Enumerable.Repeat(outputValue, 1);
});

您甚至可以将其概括为FilterBlock<T>具有过滤谓词的 a,并通过适当的匹配(就像Where在 LINQ 中一样)。您最初可以使用TransformManyBlock上述方法实现此功能,但稍后会提高效率。

于 2012-10-31T18:01:03.363 回答
6

一个有点老的问题,想在这里补充一些经验:您可以为您的数据引入aBufferBlock而不是,并使用带有条件谓词的扩展方法,因此有效值将转到,而无效值将被忽略。要丢弃它们,您可以简单地使用块,它只是忽略它接收到的数据。所以最终的代码可能如下所示:ActionBlockLinkToTransformBlockNullTarget

var input = new BufferBlock<int>();
var tb = new TransformBlock<int, int>(i => i * 2);
var output = new BufferBlock<int>();

// valid integers will pass to the transform
input.LinkTo(tb, i => ValidateInput(i));

// not valid will be discarded
input.LinkTo(DataflowBlock.NullTarget<int>());

// transformed data will come to the output
tb.LinkTo(output);

也可以通过DataflowLinkOptions其他重载LinkTo调整链接。

于 2016-11-04T16:41:27.583 回答