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));
}
}
答案 0 :(得分:16)
有几种方法可以做到这一点:
TransformManyBlock
并返回包含1或0项的集合。TransformBlock
表示“无值”的特殊值(例如null
),然后使用带有过滤器的LinkTo()
来删除这些值。您还必须在不使用过滤器的情况下将TransformBlock
链接到空块(DataflowBlock.NullTarget<T>()
),以排空特殊值。我认为这是一种黑客行为,但你也可以使用基于Task
的{{1}}构造函数:当你想要返回一些内容时使用TransformBlock
{ {1}}当你不这样做时。例如:
Task.FromResult()
答案 1 :(得分:8)
我自己没有使用过DataFlow,但我认为你可以使用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>
只具有过滤谓词,并通过适当的匹配(就像LINQ中的Where
一样)。您最初可以使用TransformManyBlock
执行此操作,但之后会更高效。
答案 2 :(得分:1)
有点老问题,想在这里添加一些经验:你可以为你的数据引入BufferBlock
而不是ActionBlock
,并使用LinkTo
扩展方法和条件谓词,所以有效值将继续到TransformBlock
,无效值将被忽略。要丢弃它们,您只需使用NullTarget
块,它只会忽略它收到的数据。所以最终的代码可能如下所示:
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
{/ 3}来调整某些other LinkTo
overload的链接。