在我的应用程序中,我想用替换值字典连接多个字符串。
readTemplateBlock
获取FileInfos并将其内容作为字符串返回
getReplacersBlock
用一个替换词典获得(一次)
joinTemplateAndReplacersBlock
应将readTemplateBlock
的每个项目加入一个getReplacersBlock
结果。
在我目前的设置中,它要求我为我发布的每个文件再次发布相同的替换词典。
// Build
var readTemplateBlock = new TransformBlock<FileInfo, string>(file => File.ReadAllText(file.FullName));
var getReplacersBlock = new WriteOnceBlock<IDictionary<string, string>>(null);
var joinTemplateAndReplacersBlock = new JoinBlock<string, IDictionary<string, string>>();
// Assemble
var propagateComplete = new DataflowLinkOptions {PropagateCompletion = true};
readTemplateBlock.LinkTo(joinTemplateAndReplacersBlock.Target1, propagateComplete);
getReplacersBlock.LinkTo(joinTemplateAndReplacersBlock.Target2, propagateComplete);
joinTemplateAndReplacersBlock.LinkTo(replaceTemplateBlock, propagateComplete);
// Post
foreach (var template in templateFilenames)
{
getFileBlock.Post(template);
}
getFileBlock.Complete();
getReplacersBlock.Post(replacers);
getReplacersBlock.Complete();
我缺少一个更好的街区吗?也许我忽略了配置选项?
答案 0 :(得分:2)
我无法弄清楚如何使用内置的数据流块来做到这一点。我可以看到的替代方案:
使用BufferBlock
小BoundedCapacity
以及Task
继续向其发送值。 Task
获取值的确切方式可能会有所不同,但如果您喜欢WriteOnceBlock
,则可以重复使用并封装它:
static IPropagatorBlock<T, T> CreateWriteOnceRepeaterBlock<T>()
{
var target = new WriteOnceBlock<T>(null);
var source = new BufferBlock<T>(new DataflowBlockOptions { BoundedCapacity = 1 });
Task.Run(
async () =>
{
var value = await target.ReceiveAsync();
while (true)
{
await source.SendAsync(value);
}
});
return DataflowBlock.Encapsulate(target, source);
}
然后,您将使用CreateWriteOnceRepeaterBlock<IDictionary<string, string>>()
代替new WriteOnceBlock<IDictionary<string, string>>(null)
。
编写类似于WriteOnceBlock
的自定义块,其行为完全符合您的要求。看看the source of WriteOnceBlock
有多大,这可能不太吸引人。
使用TaskCompletionSource
代替数据流块。
假设您当前的代码看起来像这样(为简洁起见使用C#7和System.ValueTuple
包):
void ReplaceTemplateBlockAction(Tuple<string, IDictionary<string, string>> tuple)
{
var (template, replacers) = tuple;
…
}
…
var getReplacersBlock = new WriteOnceBlock<IDictionary<string, string>>(null);
var replaceTemplateBlock = new ActionBlock<Tuple<string, IDictionary<string, string>>>(
ReplaceTemplateBlockAction);
…
getReplacersBlock.Post(replacers);
您可以使用:
void ReplaceTemplateBlockAction(string template, IDictionary<string, string>>> replacers)
{
…
}
…
var getReplacersTcs = new TaskCompletionSource<IDictionary<string, string>>();
var replaceTemplateBlock = new ActionBlock<string>(
async template => ReplaceTemplateBlockAction(template, await getReplacersTcs.Task));
…
getReplacersTcs.SetResult(replacers);