Niniejszy post jest kontynuacją cyklu o Reactive Extensions dla .NET ([RX 1], [RX 2], [RX 3], [RX 4], [RX 5], [RX 6], [RX 7], [RX 8]), dotyczyć on będzie możliwości wykorzystania LINQ na obserwowalnych kolekcjach i w RX.
W uproszczeniu Language INtegrated Query (LINQ) to część technologii .NET i umożliwia zadawanie pytań na obiektach, a składnia LINQ przypomina trochę SQL (patrz Wikipedia). Cechą charakterystyczną LINQ jest to, że operuje ona na dowolnych kolekcjach oferujących iterator (czyli operuje na IEnumerable). Więcej na temat iteratora i IEnumerable wspominane było w artykule: "Kolekcje, to podstawa, czyli wprowadzenia do Reactive Extensions część 2". Warto również pamiętać, że siła i bogactwo LINQ tkwi w metodach rozszerzających dla kolekcji. Nie ważne, więc czy skorzystamy ze specjalnej składni (typu: from sth in sth select sth), czy wykorzystamy bezpośrednio metody rozszerzające. W tym wpisie jednak nie pora na tłumaczenie, czym jest LINQ, istotna jest możliwość wykorzystania LINQ na obserwowalnych kolekcjach. Dzięki takiemu podejściu przekształcamy pewną obserwowalną kolekcję w inną o zadanych przez nas parametrach.
Może to być przydatne, by np. przefiltrować kolekcję (np. w przypadku obserwowalnej kolekcji liczb całkowitych jesteśmy zainteresowani tylko liczbami parzystymi lub np. nie interesują nas dwa pierwsze elementy i jesteśmy zainteresowani tylko czterema pozostałymi). Dla przykładu przeanalizujmy poniższy kod:
IObservable<int> obs = Observable.Create<int>( observer => { for ( int i = 0; i < 10; i++ ) { observer.OnNext( i ); } observer.OnCompleted(); return ( () => { } ); } ); Console.WriteLine( "test collection (no change):" ); using ( obs.Subscribe( x => Console.Write( "{0}, ", x ) ) ) { } Console.WriteLine(); var obs2 = from o in obs where o % 2 == 0 select o; Console.WriteLine( "from o in obs where o%2==0 select o :" ); using ( obs2.Subscribe( x => Console.Write( "{0}; ", x ) ) ) { } Console.WriteLine(); var obs3 = obs.Skip( 2 ).Take( 4 ); Console.WriteLine( "obs.Skip(2).Take( 4 ) :" ); using ( obs3.Subscribe( x => Console.Write( "{0}; ", x ) ) ) { } Console.WriteLine(); var obs4 = obs.Sum(); Console.WriteLine( "obs.Sum() :" ); using ( obs4.Subscribe( x => Console.Write( "{0}; ", x ) ) ) { } Console.WriteLine(); var obs5 = obs.Average(); Console.WriteLine( "obs.Average() :" ); using ( obs5.Subscribe( x => Console.Write( "{0}; ", x ) ) ) { } Console.WriteLine();
Którego wykonanie wypisze na ekranie:
test collection (no change): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, from o in obs where o%2==0 select o : 0; 2; 4; 6; 8; obs.Skip(2).Take( 4 ) : 2; 3; 4; 5; obs.Sum() : 45; obs.Average() : 4,5;
Powyższy przykład bazuje na prostej i „zimnej” kolekcji, ale wykorzystanie LINQ może być jeszcze ciekawsze w przypadku „ciepłych” źródeł danych np. Zdarzeń (events). Problem z filtrowaniem zdarzeń był już wspomniany w artykule „Zdarzenia w .NET niby pożyteczne, łatwe, ale … obserwowanie w Reactive Extensions jest lepsze”, teraz będąc w posiadaniu wiedzy o obserwowalnych kolekcjach tworzonych na podstawie zdarzeń oraz o wiedząc o możliwości wykorzystania LINQ na obserwowalnych kolekcjach zauważcie jak prosto można wspomniane zdarzenia filtrować lub modyfikować. Dlatego Reactive Extensions określane jest czasem mianem „LINQ to Events”.
Brak komentarzy:
Prześlij komentarz