c# – 用于将单个结果与多个其他结果连接的数据块

在我的应用程序中,我想要使用替换值字典来连接多个字符串.

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);
点赞