www.rolandk.de
- Aktuelle Themen zu .Net -
Achtung: Hier handelt es sich um meine alte Seite.
Die aktuelle ist unter folgendem Link erreichbar: www.rolandk.de/wp/
Home Blog Erste Erfahrungen mit System.Reactive




















































Erste Erfahrungen mit System.Reactive
Mittwoch, den 08. Februar 2012 um 21:53 Uhr

Vor einer ganzen Weile habe ich bei einem Vortrag von Gregor Biswanger über die Reactive Extensions von Microsoft zugehört und war zunächst gleichzeitig etwas geschockt (von der ungewohnten Syntax) und verblüfft (von der Erleichterung, die man dadurch bekommt). Wenn nicht ganz klar ist, für was dieses Framework da ist, dann genügt eigentlich schon ein Besuch bei Google. Einfach mal auf der Suchleiste das Tippen anfangen, und was passiert? Noch während dem Tippen erscheinen erste Sucherergebnisse, die auch laufend aufgefrischt werden. Die Oberfläche reagiert sofort. Die Reactive Extensions sind genau dazu da, solche Situationen für den Entwickler leicht steuerbar zu machen.

 

Man stelle sich vor, man müsste obige Logik mit Standard-Mitteln entwickeln. Man muss sich auf verschiedene Ereignisse der Eingabebox hängen, dafür sorgen, dass bei Änderungen die entsprechenden Webdienste asynchron aufgerufen werden, dafür sorgen, dass sie nicht zu oft aufgerufen werden, und, und, und.. am Ende hat man für eine Textbox schnell ein paar Hundert Zeilen Spaghetti-Code. Mit System.Reactive kann man solche Logik in ein paar Zeilen definieren - so zumindest die Musterbeispiele, übrigens auch eines aus dem oben erwähnten Vortrag. Doch soweit will ich in diesem kurzen Beitrag erst einmal gar nicht gehen, ich selbst hatte genau so einen Use-Case auch noch nie. Was aber macht das ReactiveFramework anders? Nachfolgend ein kurzes Beispiel, in dem ich mich an ein Ereignis eines Controls hänge (KeyPress) und direkt darauf eine Funktion ausführe:

  1. Observable.FromEventPattern<KeyPressEventArgs>(control, "KeyPress")
  2. .Subscribe((eArgs) => Console.WriteLine("Pressed key: " + eArgs.EventArgs.KeyChar));

Die Reactive Extensions bauen komplett auf das Observer-Pattern auf. Bei dem Beispiel oben wird ein Observer erstellt, der sich an das KeyPress-Ereignis eines Controls anhängt. Die Subscribe-Methode schließlich wird für jedes geworfene Ereignis aufgerufen. Sieht zunächst etwas primitiv aus, aber es geht natürlich noch etwas mehr.

  1. Observable.FromEventPattern<EventArgs>(control, "KeyPress")
  2. .Where((eArgs) => eArgs.EventArgs.KeyChar == 'a')
  3. .Subscribe((eArgs) => Console.WriteLine("Pressed key: " + eArgs.EventArgs.KeyChar));

Zugegeben, macht jetzt nicht wirklich viel Sinn, aber man sieht schon, wohin die Reise geht. Mit dem Where wird jetzt ein neuer Observer dazwischen geschaltet, der die Ereignisse einschränkt, also quasi wie ein Filter wirkt. Subscribe wird hier nur noch aufgerufen, wenn es der Benutzer ein 'a' getippt hat. Jetzt das nächste Beispiel.

  1. Observable.FromEventPattern<EventArgs>(control, "KeyPress")
  2. .Merge(Observable.FromEventPattern<EventArgs>(control, "TextChanged"))
  3. .Subscribe((eArgs) => Console.WriteLine("Any event was raised.."));

In diesem Fall hier ist es genau anders herum, das Ereignis wird nämlich nicht gefiltert, sondern es wird zusätzlich das Ereignis TextChanged überwacht. Jetzt wird die Subscribe Methode aufgerufen, wenn entweder das KeyPress, oder das TextChanged Ereignis ausgelöst wird. Neben diesen einfachen Beispielen will ich noch ein etwas Komplexeres zeigen.

  1. Observable.FromEventPattern<EventArgs>(control, "KeyPress")
  2. .Merge(Observable.FromEventPattern<EventArgs>(control, "TextChanged"))
  3. .Throttle(TimeSpan.FromSeconds(1.0))
  4. .SubscribeOn(SynchronizationContext.Current)
  5. .Subscribe((eArgs) => Console.WriteLine("Any event was raised.."));

Sieht jetzt schon etwas komplizierter aus. Was hier passiert: Die Ereignisse KeyPress und TextChanged werden überwacht, Subscribe wird aber nur ausgelöst, wenn nach dem Eintreten eines Ereignisses über die Zeitspanne von einer Sekunde (Throttle) kein weiteres Ereignis gekommen ist. Also egal, wie lange der Benutzer an dem Control tippt, immer eine Sekunde nach dem jeweils letzten getippten Buchstaben wird die Subscribe Methode aufgerufen. SubscribeOn kümmert sich schließlich noch darum, dass Subscribe auch im Gui-Thread aufgerufen wird. Das Gleiche Beispiel ohne Reactive Extensions, also z. B. mit Timer gesteuert, würde schon etwas komplizierter aussehen..

 

Besonders das eben gezeigte Throttle verwende ich im Moment relativ gerne, um bewusst nach einer ganzen Sequenz an Ereignissen eine bestimmte Logik auszulösen. Dabei muss es sich nicht unbedingt um Eingabeflächen handelt. Das gleiche Verfahren lässt sich etwa auch bei einer Liste von CheckBoxen anwenden, die etwa steuert, welche Ebenen in einer Grafikansicht sichtbar sind, und welche nicht. Ein anderer Fall ist etwa eine komplexere Integritätsprüfung automatisch nachdem eine ganze Menge PropertyChanged Ereignisse von einem Datenmodell gekommen sind. Im Großen und Ganzen also ein schönes kleines Spielzeug, das bei richtiger Verwendung auch einen großen Nutzen bringen kann.

 

Kommentar hinzufügen

Ihr Name:
Kommentar: