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
Kontynuując tematykę kombinatorów. Dzisiaj o pewnym znanym słówku, bardzo popularnym formacie kompresji danych. Nie wiem jakim cudem trafił do Rx-owej rodziny. Być morze przytaczam złą aluzję. Ale o tym nieco dalej.
Observable.Zip
Z angielskiego Zip znaczy tyle co zamek błyskawiczny. I tym porównaniu możemy doszukać się aluzji. Działanie operatora Observable.Zip dokładnie można zrozumieć jako zamykanie zamka. Tym samym łączymy lewą i prawą część. Utworzony zostaje nowy strumień (zamknięty zamek).
Jednak na samym początku szarpnąłem się i stworzyłem dwie klasy pomocnicze PrintExtensions, oraz ConvertingExtensions. Śledząc internety natrafiłem na takie Extension Methods dzięki którym znacznie łatwiej i czytelniej jest wyświetlać dane w konsoli.
Przy pomocy DefaultPrint możemy w szybki sposób dokonać zapisu na strumień i wyświetlać skutki działania dystrybutora danych.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static IDisposable DefaultPrint<T>(this IObservable<T> source, string identify)
{
var subscription = source.Subscribe(
item =>
{
Console.WriteLine("{0}\t\titem: {1}", identify, item);
},
exception =>
{
Console.WriteLine("{0}\t\texception: {1}", identify, exception);
},
() =>
{
Console.WriteLine("{0}\t\tcompleted", identify);
});
Druga klasa natomiast dotyczy konwertowania danych. W tym konkretnym przypadku ToCharacter wykonujemy zamianę danych typu long na ciąg znaków. Wykonujemy taką operację przez wyselekcjonowanie i zamianę wykonaną przy pomocy char.ConvertFromUtf32.
1
2
3
4
5
public static class ConvertingExtensions
{
public static IObservable<string> ToCharacter(this IObservable<long> source)
{
return source.Select(item => char.ConvertFromUtf32((int)item));
Przechodząc do meritum dzisiejszego posta, przedstawiam poniżej wycinek kodu zawierający dwa obiekty publikujące cyklicznie dane. Jeden z nich będzie dostarczał dane typu long (observableIntervalForNumbers). Natomiast drugi przy pomocy wspomnianej wcześniej metodzie ToCharacter dostarczał będzie znaki.
W przypadku Observable.Zip, nie musimy się martwić o to, że dane są różnego typu. Nowy strumień będzie dostarczał je w dwóch odpowiednio nazwanych polach (Index, Character).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var observableIntervalForNumbers = Observable.Interval(TimeSpan.FromMilliseconds(10))
.Take(256);
var observableIntervalForChars = Observable.Interval(TimeSpan.FromMilliseconds(50))
.Take(256)
.ToCharacter();
var subscription1 = observableIntervalForNumbers
.Zip(observableIntervalForChars, (leftItem, rightItem) => new
{
Index = leftItem,
Character = rightItem
})
.DefaultPrint("Zip test");
Na samym końcu korzystając z metody DefaultPrint wyrzucamy interesujące dane znajdujące się w źródełku. Używanie Zip jest bardzo proste, z głównego strumienia wywołujemy metodę i w parametrach podajemy drugi strumień z jakim będzie zip-owany. Jako drugi parametr podajemy lambdę, której celem będzie utworzenie obiektu z obu łączonych właściwości.
Zakończenie
Co jest ciekawe publikowanie na zip-owany strumień nastąpi dopiero gdy oba źródłowe strumienie wyślą swoją jednostkę danych. Zip:.color_2} poczeka, aż z obu strumieni dotrą dane.
To tyle w ten piątkowy wieczór. Po przeczytaniu posta mam cichą nadzieję, że od tej pory zamek błyskawiczny będzie miał też bardzie przyzwoite zastosowanie.
Kod z Wami!
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 - Kombinatorzy - Merge
Następny: Programowanie Reaktywne - Kombinatorzy - Switch