.Net Reactive Extension ger utvecklare en uppsättning funktioner för att implementera en reaktiv programmeringsmodell för .Net-utvecklare för att göra händelsehanteringen enklare och mer uttrycksfull med deklarativa åtgärder. Även om de viktigaste hörnstenarna för reaktiv skalning är IObserver- och IObservable-gränssnitten, behöver du som utvecklare ofta inte implementera dessa gränssnitt själv. Biblioteket stöder den inbyggda typen Subject<T>, som implementerar gränssnitt och stöder många funktioner.
Teman utgör grunden för de olika ämnen som finns tillgängliga i biblioteket, och det finns andra teman – ReplaySubject<T>, BehaviorSubject<T> och AsyncSubject<T>. Det är användbart att förstå de grundläggande skillnaderna mellan dem och hur man använder dem för att bättre utnyttja biblioteket.
I denna artikel kommer vi att jämföra Subjektet<T> och dess syskon, och försöka illustrera skillnaderna mellan deras beteenden.
Subjekt<T>
Som nämnts tidigare<T> är Subject grunden för de tillgängliga teman och ger ett enkelt sätt att använda biblioteket utan att själv behöva implementera IObservable<T> och IObserver-gränssnitten<T>. En enkel demonstration av tematypen visas nedan.
I koden ovan skapade vi en <T>instans av Subject, och eftersom den implementerar<T> IObserver och IObserverable<T>, använder vi samma instans för att prenumerera och publicera värdet till IObserver. En annan viktig punkt att notera här är hur vi använder överbelastningen i Subscribe-metoden för att acceptera handlingar som indata. Detta görs för varje publicerat värde, i detta fall när numret skrivs ut till konsolen.
Låt oss försöka visa de publicerade värdena och de värden som IObserver (i denna åtgärd<T>) skriver ut till konsolen i följande bild. Detta hjälper oss att enkelt jämföra de kvarvarande syskonen och varianterna.
Den första raden representerar det publicerade värdet och den andra raden representerar värdet som mottagits av IObservern. Dessutom har vi lagt till en rad för att ange vid vilken punkt observatören prenumererar på strömmen under utförandet. Denna linje representeras av en vertikal streckad linje.
I koden ovan märkte vi att observatören prenumererade på dataströmmen innan det första värdet publicerades. Bilden visar prenumerationsraden placerad före det första elementet. Som du kan se från utgångslinjen har detta ingen effekt på utgången (vid denna punkt).
Men vad händer om observatören bara prenumererar på data efter att vissa värden redan har publicerats? Påverkar detta de data som tas emot av observatörer? Innan vi tittar på utdatan, låt oss skriva samma kod först.
I koden ovanför kan vi observera att observatören prenumererar på dataströmmen först efter att två värden (1 och 2) har publicerats. Som man kan förvänta sig kommer detta att göra att observatörer inte får data som publiceras innan prenumerationsmetoden anropas. Som visas i figuren nedan.
Vad händer om du vill läsa alla publicerade värden, även om observatören prenumererar sent? Det är här ReplaySubject kommer in i<T> bilden.
ReplaySubject<T>
ReplaySubject<T> cachar värden och spelar upp dem för senare prenumeranter. Detta är användbart för att undvika tävlingsförhållanden. Låt oss ändra den tidigare koden till att använda ReplaySubject<T> och se hur den påverkar vad observatören får.
Som visas i koden ovan sker<T> <T>knappt någon förändring i koden förutom att vi nu använder ReplaySubject istället för subject. Följande diagram illustrerar effekten på de data som observatören mottagit.
Som visas på bilden spelas det cachade värdet nu upp för abonnenten även om abonnenten prenumererar senare. Självklart kommer denna användbara funktion med ett pris. Denna implementation kommer att cachelagra varje värde som publiceras av abonnenten, vilket kan orsaka dåliga minnesproblem när datamängden är betydligt större.
Men ReplaySubject<T> har mer än ett sätt att lösa detta problem. För detta exempel ska vi titta på två exempel som använder storleks- och tidsbegränsningar för att begränsa det cachelagrade värdet.
I det första fallet kommer vi att använda cachens storlek för att begränsa cachens värde. <T>ReplaySubjects konstruktör tillhandahåller en överbelastning, som accepterar ett heltal som representerar cachebuffertens storlek (maximalt elementantal). I vårt exempel ändrar vi koden för att begränsa cachestorleken till 1.
Observera hur vi använder <T>ReplaySubjects konstruktöröverbelastning för att ange cachens storlek som 1. Detta begränsar caching och säkerställer att endast ett element cachas och ersätts med ett nytt så snart det publiceras. Förändringens påverkan visas nedan.
Ett annat sätt att begränsa caching är att begränsa tiden för det cachade objektet, eller med andra ord, att ange en utgångstid för det cachade objektet.
Låt oss skriva kod för att illustrera det exemplet.
Liknande den tidigare koden använder vi<T> överbelastningen i ReplaySubject-konstruktorn för att specificera utgångstiden för objekt i cachen. För att visa vårt fall införde vi en fördröjning mellan utsläppet av värden.
Eftersom det tar hela 1200 ms innan observatören prenumererar, kommer alla element som överstiger 1000 ms utgångstid att tas bort från cachen. I detta exempel kommer detta att göra att värde 1 tas bort från cachen och inte spelas upp för sena prenumeranter. Som visas i figuren nedan.
Det <T>finns andra överbelastningar för ReplaySubject som ger mer flexibilitet och finjusterar de cachelagrade värdena, men till exempel behåller vi de två exemplen som redan täckts ovan.
Beteendeämne<T>
BehaviourSubject <T>är mycket likt ReplaySubject<T> eftersom det hjälper till att cachelagra värden. Men det finns en betydande skillnad. BehaviourSubject<T> cachar endast det senast publicerade värdet. Innan vi går in på det här vidare, låt oss skriva lite kod.
Om BehaviorSubject<T> bara cachar ett enda värde (som är senast känt), hur skiljer det sig då från en ReplaySubject av storlek 1<T>? Följande diagram återspeglar tydligt situationen för koden ovan.
Detta är dock inte helt sant. Det finns två viktiga skillnader att förstå här. Den första är närvaron av standardinställningar. Observera att vi i koden ovan <T>anger värdet 0 som standard i konstruktören av BehaviourSubject. Om inget värde finns i cachen (eller med andra ord, ingen data publicerades innan observatören prenumererade), kommer standardvärdet att returneras. Detta skiljer sig från ReplaySubject, som har storleken 1<T>, vilket inte har något värde. Följande kod och en visuell representation av sekvensen demonstrerar detta beteende.
Den andra skillnaden är hur BehaviorSubject<T> och ReplaySubject<T> beter sig när de prenumererar på en färdig sekvens. När du prenumererar efter att ha slutfört kommer BehaviorSubject <T> inte ha något värde, som visas i koden nedan.
Prenumeranter garanteras att inte få något värde eftersom prenumerationer sker efter att de är klara.
Detta gäller dock <T>ReplaySubject. Det finns ingen garanti för att observatören inte får några värden, som visas i koden nedan.
Som visas i koden ovan är cachen 1 i storlek och även om prenumerationen anropas efter att samtalet är slutfört, kommer cachen att finnas kvar (tills utgångsvillkoret uppfylls), så i detta fall kommer det senast publicerade värdet att tas emot.
AsyncSubjekt<T>
AsyncSubject <T>är det sista syskonet till Subjektet som vi kommer att utforska i denna artikel<T>, och det liknar mycket de två tidigare (ReplaySubject och BehaviourSubject) genom att det också cachelagrar resultat. Men återigen finns det en betydande skillnad. AsyncSubject publicerar det senast cachade värdet endast om sekvensen är markerad som komplett <T> (den cachar endast ett värde, det sista värdet).
Betrakta följande kod.
Detta genererar ett värde för observatören att sekvensen markeras som det sista värdet som publicerades före slutförandet – värde 4. Som visas i figuren nedan.
Men vad händer om vi hoppar över samtalet som markerar sekvensen som slutförd? Låt oss kommentera ut raden och försöka igen.
Detta genererar ingen data för observatören eftersom AsyncSubject<T> publicerar resultat först efter att sekvensen markerats som slutförd.
Detta är en betydande skillnad som alla som använder AsyncSubject <T>bör ha i åtanke.
slutsats
Denna artikel visar <T>skillnaderna mellan de olika syskonen i Subject och några av dess variationer. Det är ofta användbart att vara medveten om dessa subtila skillnader, eftersom de kan uppvisa ett annat beteende än du förväntat dig om du inte inser det.
Originallänk:Inloggningen med hyperlänken är synlig.
|