在我的应用程序中,我想要使用替换值字典来连接多个字符串.
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();
我错过了一个更好的街区吗?也许我忽略了一个配置选项?
最佳答案 我无法弄清楚如何使用内置的数据流块来做到这一点.我可以看到的替代方案:
>使用具有小BoundedCapacity的BufferBlock以及不断向其发送值的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>>()而不是新的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);