Concurrency in CSharp Cookbook中文翻译:5.6创建自定义块

Problem 问题

You have reusable logic that you want to place into a custom dataflow block.Doing so enables you to create larger blocks that contain complex logic.
您希望将可重用的逻辑放入自定义数据流块中。这样做可以创建包含复杂逻辑的更大的块。

Solution 解决方案

You can cut out any part of a dataflow mesh that has a single input and output block by using the Encapsulate method. Encapsulate will create a single block out of the two endpoints. Propagating data and completion between those endpoints is your responsibility. The following code creates a custom dataflow block out of two blocks, propagating data and completion:
通过使用encapsulation方法,您可以删除具有单个输入和输出块的数据流网格的任何部分。encapsulation将从两个端点中创建一个单独的块。在这些端点之间传播数据和完成是您的责任。下面的代码用两个块创建了一个自定义数据流块,传播数据和完成:
IPropagatorBlock<int, int> CreateMyCustomBlock()
{
    var multiplyBlock = new TransformBlock<int, int>(item => item * 2);
    var addBlock = new TransformBlock<int, int>(item => item + 2);
    var divideBlock = new TransformBlock<int, int>(item => item / 2);
    var flowCompletion = new DataflowLinkOptions { PropagateCompletion =true };
    multiplyBlock.LinkTo(addBlock, flowCompletion);
    addBlock.LinkTo(divideBlock, flowCompletion);
    return DataflowBlock.Encapsulate(multiplyBlock, divideBlock);
}

Discussion 讨论

When you encapsulate a mesh into a custom block, consider what kind of options you want to expose to your users. Consider how each block option should (or shouldn’t) be passed on to your inner mesh; in many cases, some block options don’t apply or don’t make sense. For this reason, it’s common for custom blocks to define their own custom options instead of accepting a DataflowBlockOptions parameter.
当您将网格封装到自定义块中时,请考虑您希望向用户公开什么样的选项。考虑每个块选项应该(或不应该)如何传递到你的内部网格;在许多情况下,一些块选项不适用或没有意义。出于这个原因,自定义块通常定义自己的自定义选项,而不是接受DataflowBlockOptions参数。
DataflowBlock.Encapsulate will only encapsulate a mesh with one input block and one output block. If you have a reusable mesh with multiple inputs and/or outputs, you should encapsulate it within a custom object and expose the inputs and outputs as properties of type ITargetBlock<T> (for inputs) and IReceivableSourceBlock<T> (for outputs).
DataflowBlock。封装将只封装一个输入块和一个输出块的网格。如果你有一个具有多个输入和/或输出的可重用网格,你应该将其封装在一个自定义对象中,并将输入和输出作为 ITargetBlock<T>(用于输入)和IReceivableSourceBlock<T>(用于输出)。
These examples all use Encapsulate to create a custom block. It is also possible to implement the dataflow interfaces yourself, but it’s much more difficult. Microsoft has a paper that describes advanced techniques for creating your own custom dataflow blocks.

这些示例都使用了封装来创建自定义块。也可以自己实现数据流接口,但要困难得多。微软有一篇论文描述了创建自定义数据流块的高级技术。