2012-10-31 12 views
13

TPL Dataflow इनपुट बदलने के लिए एक TransformBlock प्रदान करता है, उदा .:छोड़ें आइटम

var tb = new TransformBlock<int, int>(i => i * 2); 

यह संभव उत्पादन नहीं करने के लिए इनपुट, उदा में से कुछ है अगर इनपुट कुछ सत्यापन परीक्षण विफल रहता है?

var tb = new TransformBlock<InputType, OutputType>(i => 
{ 
    if (!ValidateInput(i)) 
    { 
     // Do something to not output anything for this input 
    } 
    // Normal output 
} 

यदि यह संभव नहीं है, तो अंत को प्राप्त करने के लिए सबसे अच्छा पैटर्न क्या होगा?
कुछ निम्नलिखित की तरह है?

BufferBlock<OutputType> output = new BufferBlock<OutputType>(); 

var ab = new ActionBlock<InputType>(i => 
{ 
    if (ValidateInput(i)) 
    { 
     output.Post(MyTransform(i)); 
    } 
} 

उत्तर

11

वहाँ ऐसा करने के तरीके पर कई विकल्प हैं:

  1. उपयोग TransformManyBlock जॉन के रूप में सुझाव दिया है और एक संग्रह 1 या 0 आइटम लौटाएगा।
  2. "कोई मूल्य" (उदा। null) का प्रतिनिधित्व करने वाले कुछ विशेष मूल्य के साथ TransformBlock का उपयोग करें और फिर उनको हटाने के लिए फ़िल्टर के साथ LinkTo() का उपयोग करें। विशेष मूल्यों को निकालने के लिए आपको फ़िल्टर के बिना TransformBlock को शून्य ब्लॉक (DataflowBlock.NullTarget<T>()) से लिंक करना होगा।
  3. मैं एक हैक की यह कुछ पर विचार करेंगे, लेकिन आप भी TransformBlock की Task आधारित निर्माता का उपयोग कर सकते हैं: Task.FromResult() का उपयोग जब आप कुछ और null वापस जाने के लिए जब तुम नहीं चाहते हैं। उदाहरण के लिए:

    new TransformBlock<int, int>(i => i % 2 == 0 ? Task.FromResult(i * 2) : null) 
    
8

मैं अपने आप को dataflow उपयोग नहीं किया है, लेकिन मैं आप एक TransformManyBlock इस्तेमाल कर सकते हैं लगता है , और बस हर कदम वापसी या तो एक खाली संग्रह या एक आइटम बनाते हैं।

var tmb = new TransformManyBlock<InputType, OutputType>(i => 
{ 
    if (!ValidateInput(i)) 
    { 
     return Enumerable.Empty<OutputType>(); 
    } 
    ... 
    // Or return new[] { outputValue }; 
    return Enumerable.Repeat(outputValue, 1); 
}); 

तुम भी संभवतः एक FilterBlock<T> जो सिर्फ एक फ़िल्टर विधेय है, और (LINQ में Where जैसे) के माध्यम से उचित मैचों गुजरता को यह सामान्यीकरण सकता है। आप शुरुआत में TransformManyBlock का उपयोग करके इसे कार्यान्वित कर सकते हैं, लेकिन फिर इसे बाद में अधिक कुशल बना सकते हैं।

1

थोड़ा सा पुराना सवाल, यहाँ कुछ अनुभव जोड़ना चाहते हैं: आप एक BufferBlock अपने डेटा के लिए ActionBlock के बजाय लागू कर सकते हैं, और हालत विधेय के साथ LinkTo विस्तार विधि, इसलिए वैध का उपयोग मान TransformBlock पर आगे बढ़ेंगे, और अमान्य लोगों को अनदेखा कर दिया जाएगा। उन्हें हटाने के लिए आप बस NullTarget ब्लॉक का उपयोग कर सकते हैं, जो इसे प्राप्त होने वाले डेटा को आसानी से अनदेखा करता है। तो अंतिम कोड ऐसा दिखाई दे सकता:

var input = new BufferBlock<int>(); 
var tb = new TransformBlock<int, int>(i => i * 2); 
var output = new BufferBlock<int>(); 

// valid integers will pass to the transform 
input.LinkTo(tb, i => ValidateInput(i)); 

// not valid will be discarded 
input.LinkTo(DataflowBlock.NullTarget<int>()); 

// transformed data will come to the output 
tb.LinkTo(output); 

इसके अलावा जोड़ने other LinkTo overload के साथ कुछ DataflowLinkOptions के साथ समायोजित किया जा सकता है।

+0

यह अनिवार्य रूप से विकल्प (2) svick के उत्तर में है। –

+0

@ गॉर्डनबीन ब्लॉक के बीच अतिरिक्त सीधा लिंक के साथ – VMAtm

संबंधित मुद्दे