czwartek, 5 stycznia 2012

[RX 9] Operacje LINQ na obserwowalnych kolekcjach w Reactive Extension [PL]

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”.

Promuj

Brak komentarzy:

Prześlij komentarz

Posty powiązane / Related posts