2012-10-31 19 views
13

TPL Dataflow zapewnia TransformBlock przekształcania wejście, np .:Pomiń Pozycja w dataflow TransformBlock

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

Czy to możliwe, aby nie wyjście niektóre wejścia, np jeśli dane wejściowe nie zawierają testu sprawdzającego poprawność?

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

Jeśli nie jest to możliwe, jaki byłby najlepszy wzór do osiągnięcia tego celu?
Coś jak poniżej?

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

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

Odpowiedz

11

Istnieje kilka opcji, w jaki sposób to zrobić:

  1. Zastosowanie TransformManyBlock jak Jon je i zwraca zbiór zawierający 1 lub 0 elementów.
  2. Użyj wartości specjalnej oznaczającej "brak wartości" (na przykład null), a następnie użyj LinkTo() z filtrem, aby je usunąć. Musisz również połączyć TransformBlock z pustym blokiem (DataflowBlock.NullTarget<T>()) bez filtra, aby spuścić specjalne wartości.
  3. uznałbym to coś hack, ale można też użyć Task opartych konstruktora TransformBlock: use Task.FromResult() gdy chcesz powrócić coś i null kiedy nie. Na przykład:

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

Nie używałem dataflow siebie, ale myślę można użyć TransformManyBlock, i po prostu zrobić każdy powrót krok albo pustą kolekcję lub pojedynczy element.

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

można nawet potencjalnie uogólnić to do FilterBlock<T> który tylko ma predykat filtru, i przechodzi przez odpowiednie mecze (podobnie jak Where w LINQ). Początkowo możesz to zaimplementować, używając TransformManyBlock jak wyżej, ale później spraw, by był bardziej wydajny.

1

trochę stare pytanie, chcesz dodać pewne doświadczenie tutaj: można wprowadzić BufferBlock zamiast ActionBlock do swoich danych i używać LinkTo metodę rozszerzenia o stan orzecznika, więc obowiązujący wartości przejdą do TransformBlock, a nieprawidłowe będą ignorowane. Aby je odrzucić, możesz po prostu użyć bloku NullTarget, który po prostu ignoruje otrzymywane dane. Więc ostateczny kod mógłby wyglądać następująco:

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

łącząc także może być regulowana z niektórymi DataflowLinkOptions z other LinkTo overload.

+0

Zasadniczo jest to opcja (2) w odpowiedzi svicka. –

+0

@GordonBean z dodanym bezpośrednim łączem między blokami – VMAtm