Artykuł ten jest częścią serii artykułów na temat Programowania reaktywnego.
Zapraszam na GitHub-a.
Tematy
- Wstęp
- Zabawa z czasem - Timer
- Kto za tym stoi? - Scheduler
- Nie zapominaj - Subscribe
- Zabawa z czasem - Interval
- Zabawa z czasem - Buffer
- Zabawa z czasem - Delay
- Zabawa z czasem - Sample
- Zabawa z czasem - Throttle
- Zabawa z czasem - Timestamp/TimeInterval
- Tworzymy dane - Generators
- Tworzymy dane - Własna klasa publikująca
- Marudzimy - Skip
- Marudzimy - Take
- Łap To! - ConsoleKey
- Kombinatorzy - Concat
- Kombinatorzy - Repeat
- Kombinatorzy - Start With
- Kombinatorzy - Ambiguous
- Kombinatorzy - Merge
- Kombinatorzy - Zip
- Kombinatorzy - Switch
- Kombinatorzy - When-And-Then
- Kombinatorzy - Combine Latest
- Transformers - Select
- Transformers - OfType and Cast
- Transformers - Metadata
- Bileciki do kontroli - Unit Tests of Interval
- Bileciki do kontroli - Unit Tests of Observer Interval
- Bileciki do kontroli - Unit Tests of Create Cold/Hot Observable
- Szpryca - AutoFac
Wstęp
Krakałem, krakałem o pechu i wykrakałem. Miało być tak szybko z drugim marudą, a tu się pojawiły problemy jakich wcześniej nie przewidziałem. Otóż drugi maruda działa na innej zasadzie. Marudzi ale przy braniu. I tutaj pojawił się problem. Bierzemy pierwsze kilka publikacji na strumień. I kasował swoją subskrypcję, co ciekawe w momencie wyzwalania przez publikację metody OnNext, tym samym dochodziło do jednoczesnego dostępu do tej samej kolekcji przez ForEach i Dispose. Po nierównej walce, obrałem obejście problemu i skorzystałem jedynie ze strumieni generowanych przez Observable.Generator:).
Take - chcę tylko to i to, tamtego już nie…
Tworzymy dwa bardzo podobne do siebie generatory. Po co jest potrzebny ten drugi dowiemy się trochę niżej. Będą one produkować dane co 100ms i 400ms. Kto się zapisze to dostanie;)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static void InitializeGenerators()
{
var initialState = 0;
_generator1 = Observable.Generate(
initialState,
condition => condition < GenerateItemCount,
iterate => iterate + 1,
resultSelector => resultSelector,
timeSelector => TimeSpan.FromMilliseconds(100)
);
_generator2 = Observable.Generate(
initialState,
condition => condition < GenerateItemCount,
iterate => iterate + 1,
resultSelector => resultSelector,
timeSelector => TimeSpan.FromMilliseconds(400)
);
I o to nasz pierwszy maruda (TakeLast), dla niego liczy się tylko ten X ostatnich publikowanych na strumień danych. Można by żec, ignorant:). Czeka, czeka, aż pojawi się to co che. Zgarnie swoją wybredną pulę danych.
1
2
3
4
5
6
7
8
private static void AddTakeLastSubscribent()
{
_generator1
.TakeLast(10)
.Subscribe(
item =>
{
Console.WriteLine($"TakeLast 10 items from {GenerateItemCount}: {item}");
TakeWhile ten ma swoje zasady. Jak strumień ich nie spełnia to nie chce danych. Jest bardzo wybredny. Oczywiście marudy należy wpiąć między strumień a subskrypcję. Jak bardzo wybredny to zależy od nas. Należy pamiętać jednak, że jeżeli choć raz coś mu nie spasuje to się i dan nogę!
1
2
3
4
5
6
7
8
private static void AddTakeWhileSubscribent()
{
_generator1
.TakeWhile(x => x < 5)
.Subscribe(
item =>
{
Console.WriteLine($"TakeWhile, show only some first generated data: {item}");
Szybki Bill (Take), od razu zgarnia dane od dystrybutorów. Jednak wybiera tylko pierwsze sztuki. To wredna bestia jak dostanie co chce, wypisze z subskrypcji 8} i tyle go widzieli…
1
2
3
4
5
6
7
8
private static void AddTakeSubscribent()
{
_generator1
.Take(10)
.Subscribe(
item =>
{
Console.WriteLine($"Take (10): {item}");
Na koniec ostatni i to tutaj właśnie potrzebny jest ten drugi generator (_generator2). Odbiera dane puki _generator1 publikuje. Jeżeli pierwszy padnie. To wówczas TakeUntil już nie chce. I oczywiście wypisze się z listy subskrybentów.
1
2
3
4
5
6
7
8
private static void AddTakeUntilSubscribent()
{
_generator2
.TakeUntil(_generator1)
.Subscribe(
item =>
{
Console.WriteLine($"TakeUntil, generator1 publishing: {item}");
Zakończenie
Dzisiejszy zestaw operatorów, dość podobny do tych z poprzedniego posta. Jedne ignorują drugie biorą. Lustrzane odbicia. Trochę napsuły mi dzisiaj krwi. Walczyłem, walczyłem, a potem zmieniłem taktykę i pokonałem problem. Warto czasem zrobić krok do tyłu by zobaczyć problem z innej perspektywy i rozwiązać go podążając inną drogą. :). Done.
Jest to post wchodzący w skład podjętego wyzwania ogłoszonego przez MIROBURN we vlogu z dnia 3 lutego 2018 roku.
Celem wyzwania jest systematyczne działanie w ciągu 30 dni.
Postanowiłem pisać post dziennie o tematyce Programowania Reaktywnego dla platformy .NET.
Wszelkie źródła związane z postami znajdują się na repozytorium GitHub.
Stan obecny wyzwania: 30 z 30 dni.
Referencje:
- MSDN - Getting Started with Rx,
- MSDN - Reactive Extensions,
- 101 Rx Samples,
- ReactiveX,
- Code Project,
- GitHub
Wcześniejszy: Programowanie Reaktywne - Marudzimy - Skip
Następny: Programowanie Reaktywne - Łap To - ConsoleKey