2012-10-31 2 views
13

TPL Dataflow fornisce TransformBlock per trasformare ingresso, es .:Skip articolo in Dataflow TransformBlock

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

'possibile non uscita alcuni degli input, ad esempio se l'input fallisce un test di validazione?

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

Se ciò non è possibile, quale sarebbe lo schema migliore per raggiungere tale scopo?
Qualcosa come il seguente?

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

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

risposta

11

Ci sono diverse opzioni su come fare questo:

  1. Usa TransformManyBlock come Jon suggerito e restituire un insieme contenente 1 o 0 articoli.
  2. Utilizzare TransformBlock con un valore speciale che rappresenta "nessun valore" (ad esempio null) e quindi utilizzare uno LinkTo() con filtro per rimuoverlo. Devi anche collegare il TransformBlock al blocco nullo (DataflowBlock.NullTarget<T>()) senza filtro, per scaricare i valori speciali.
  3. Secondo me è qualcosa di un hack, ma è anche possibile utilizzare la funzione di costruzione Task basata su di TransformBlock: utilizzare Task.FromResult() quando si vuole restituire qualcosa e null quando non lo fai. Per esempio:

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

Non ho usato DataFlow me stesso, ma mi pensare si potrebbe usare una TransformManyBlock, e basta fare ogni ritorno passo sia un insieme vuoto o di un singolo elemento.

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

Si potrebbe anche potenzialmente generalizzare questo ad un FilterBlock<T> che appena ha un predicato di filtro, e passa partite appropriate attraverso (proprio come Where in LINQ). È possibile implementarlo inizialmente usando TransformManyBlock come sopra, ma in seguito renderlo più efficiente.

1

Un po 'vecchia questione, vuole aggiungere un po' di esperienza qui: è possibile introdurre un BufferBlock invece di ActionBlock per i dati, e utilizzare LinkTo metodo di estensione con condizioni predicato, in modo che il valido i valori passeranno allo TransformBlock e quelli non validi verranno ignorati. Per scartarli è sufficiente utilizzare il blocco NullTarget, che ignora semplicemente i dati ricevuti. Quindi il codice finale potrebbe assomigliare a questo:

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

collega potrebbe anche essere regolato con una certa DataflowLinkOptions con other LinkTo overload.

+0

Questa è essenzialmente l'opzione (2) nella risposta di svick. –

+0

@GordonBean con collegamento diretto aggiunto tra i blocchi – VMAtm