Dzisiaj na szybko wrócimy z powrotem do tematu TPL Data Flows. Jakiś czas temu pisałem o różnych blokach w TPL DataFlows. Nie opisałem jednak TransformManyBlock. TransformManyBlock jest analogiczny do TransformBlock z tym, że na wyjściu jest kolekcja więc możliwe jest zwrócenie kilku wartości. TransformBlock służył wyłącznie do przetworzenia parametru i zwrócenia pojedynczego wyniku.
Ktoś może zapytać, czy to nie to samo co przekazanie jako typu generycznego IEnumerable<> do TransformBlock – też wtedy na wyjściu będzie kolekcja danych. Najlepiej to pokazać na przykładzie:
internal class Program { private static void Main() { var block = new TransformManyBlock<int, double>(number => TransformData(number)); block.LinkTo(new ActionBlock<double>(n => Display(n))); block.Post(3); Console.ReadLine(); } private static void Display(double n) { Console.WriteLine("Liczba:{0}",n); } private static IEnumerable<double> TransformData(int number) { for (int i = 0; i < number; i++) yield return i; } }
Jak widać, akcja podłączona do TransformManyBlock wciąż przyjmuje pojedynczą wartość jako parametr wejściowy. Po prostu wartości będą przekazane jedna po jednej. Zmodyfikujmy przykład, a konkretnie metodę TransformData:
private static IEnumerable<double> TransformData(int number) { for (int i = 0; i < number; i++) { yield return i; Thread.Sleep(5000); } }
Dodaliśmy opóźnienie. W momencie jednak wygenerowania pierwszej wartości, zostanie ona natychmiast przekazana do ActionBlock. Możliwe zatem, że dane częściowe z dwóch różnych źródeł danych będą przeplatać się wzajemnie. Nie będzie trzeba czekać aż wszystkie elementy kolekcji są gotowe do przekazania. Myślę, że widać sporą analogię do SelectMany. TransformBlock można porównać do Select, z kolei TransformManyBlock do SelectMany. Oba bloki to tak naprawdę projekcja danych.