2017-05-04 62 views
4

在我的應用程序中,我想要使用替換值字典連接多個字符串。將多個其他結果加入單個結果的數據塊

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(); 

有沒有更好的塊我失蹤了?也許我忽略了一個配置選項?

+2

你有沒有使用考慮'TaskCompletionSource'用於字典,而不是'WriteOnceBlock'和'JoinBlock'? – svick

+0

從來沒有聽說過他們。研究 –

+0

你能否詳細說明,也許會變成答案? –

回答

2

我想不出如何使用內置的數據流塊來做到這一點。替代方案,我可以看到:

  1. Task是保持值發送給它一起使用BufferBlockBoundedCapacity。究竟是怎樣的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)

  2. 編寫一個類似於WriteOnceBlock的自定義塊,其行爲與您想要的完全相同。看看the source of WriteOnceBlock有多大,這可能不是很吸引人。

  3. 爲此,請使用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); 
    
+0

我去了taskcompletionsource。事實證明,許多事情變得更簡單 –