在数据流库的帮助下创建自定义拆分块只需要一些帮助,该库是.Net中TPL的一部分。
我想要实现的只是一个简单的自定义块,它接受输入并将其拆分为多个transformblock。这是过滤数据所必需的,我可以在其中记录否定条目并继续使用好的条目。
根据我的需要,它应足以将输入分成两个不同的输出。类头应该看起来像这样......
public abstract class SplitBlock<TInput, TOutputLeft, TOutputRight>
我的问题是我不知道该怎么做。我所知道的是我需要两个TransformBlocks:
var leftBlock = new TransformBlock<TInput, TOutputLeft>(...)
var rightblock = new TransformBlock<TInput, TOutputRight>(...)
在我的所有尝试中,我最终都有多个ITargetBlock用于存储左右块的输入,但这不可能,是吗?
我感谢你能给予的每一个暗示。
答案 0 :(得分:5)
我首先想一想该类的通用接口应该如何。我认为最简单的解决方案是:
public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
public ITargetBlock<TInput> Input { get; }
public ISourceBlock<TOutputLeft> LeftOutput { get; }
public ISourceBlock<TOutputRight> RightOutput { get; }
}
由此,实现自然地实现:一个输入块连接到两个输出块。唯一的问题是实际处理是否应该在输出块中完成(就像你在两个TransformBlock
s中建议的那样)或在输入块中。
如果要在输出块中进行处理,输入块可以是ActionBlock
,它将输入发送到两个输出,输出将是TransformBlock
,如您所建议的那样。
public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
private ActionBlock<TInput> input;
private TransformBlock<TInput, TOutputLeft> leftOutput;
private TransformBlock<TInput, TOutputRight> rightOutput;
public ITargetBlock<TInput> Input { get { return input; } }
public ISourceBlock<TOutputLeft> LeftOutput { get { return leftOutput; } }
public ISourceBlock<TOutputRight> RightOutput { get { return rightOutput; } }
public SplitBlock(
Func<TInput, TOutputLeft> leftTransform,
Func<TInput, TOutputRight> rightTransform)
{
input = new ActionBlock<TInput>(
x =>
{
leftOutput.Post(x);
rightOutput.Post(x);
});
leftOutput = new TransformBlock<TInput, TOutputLeft>(leftTransform);
rightOutput = new TransformBlock<TInput, TOutputRight>(rightTransform);
// TODO handle fault in input correctly
input.Completion.ContinueWith(
_ =>
{
leftOutput.Complete();
rightOutput.Complete();
});
}
}
(这假设左右变换可以同时处理相同的输入。)
另一方面,如果你想在输入块中执行处理(这对我来说更有意义),那么你可以将ActionBlock
作为输入,BufferBlock
作为输出,输入块处理输入,然后将结果发送到输出块:
public class SplitBlock<TInput, TOutputLeft, TOutputRight>
{
private ActionBlock<TInput> input;
private BufferBlock<TOutputLeft> leftOutput;
private BufferBlock<TOutputRight> rightOutput;
public ITargetBlock<TInput> Input { get { return input; } }
public ISourceBlock<TOutputLeft> LeftOutput { get { return leftOutput; } }
public ISourceBlock<TOutputRight> RightOutput { get { return rightOutput; } }
public SplitBlock(
Func<TInput, Tuple<TOutputLeft, TOutputRight>> combinedTransform)
{
input = new ActionBlock<TInput>(
value =>
{
var result = combinedTransform(value);
leftOutput.Post(result.Item1);
rightOutput.Post(result.Item2);
});
leftOutput = new BufferBlock<TOutputLeft>();
rightOutput = new BufferBlock<TOutputRight>();
// TODO handle fault in input correctly
input.Completion.ContinueWith(
_ =>
{
leftOutput.Complete();
rightOutput.Complete();
});
}
public SplitBlock(
Func<TInput, TOutputLeft> leftTransform,
Func<TInput, TOutputRight> rightTransform)
: this(x => Tuple.Create(leftTransform(x), rightTransform(x)))
{}
}