Frage

.NET 4.0 Beta 2 hat IObservable und IObserver Schnittstellen.

Was sind die Vorteile im Vergleich zu klassischen .NET-Ereignissen? Ist das nicht das gleiche Problem lösen?

War es hilfreich?

Lösung

Sie können IObservable als Ereignis verwenden, Code zu ersetzen, die Ereignisse mit Eigenschaften vom Typ IObservable aussetzt, aber das ist nicht wirklich der Punkt.

Es gibt zwei wichtige Dinge über IObservable zu verstehen:

  1. Es vereint zwei Konzepte, die wir nicht wussten, wie sie vor dem vereinen. Asynchrone Operationen (die in der Regel einen einzelnen Wert zurückgeben) und Veranstaltungen (die in der Regel für immer weitergehen)

  2. Es ist zusammensetzbare . Im Gegensatz zu CLR Ereignissen, IAsyncResult oder INotifyCollectionChanged es uns bestimmte Ereignisse aus den allgemeinen Ereignissen und asynchronen Operationen erstellen kann.

Hier ist ein Beispiel, das ich in bei der Arbeit lief heute Nachmittag.

In Silverlight gibt es einige Effekte, die Sie auf eine Bildkontrolle anwenden können, die nicht auf einer normalen Kontrolle angewendet werden kann. Um das zu umgehen diese Einschränkungen, wenn ein Steuer Inhalt geändert wird ich für seine visuelle Erscheinung warten kann aktualisiert werden und einen Screenshot davon nehmen. Dann möchte ich seine visuelle Darstellung verbergen, ersetzen Sie es mit dem Snapshot und anwenden, um die visuellen Effekte auf das Bild. Jetzt kann ich Bild-Effekte auf ein Steuer anwenden (vorausgesetzt, es ist nicht interaktiv).

Dieses Programm würde trivial sein, aber die Tatsache, dass es muß asynchron sein. Ich muss für zwei aufeinanderfolgende asynchrone Operationen warten abgeschlossen ist, bevor ich Effekte auf das Bild anwenden können:

  1. Der Inhalt der Steuerung geändert
  2. Die visuelle Erscheinungsbild der Kontrolle wird aktualisiert

Hier ist, wie ich dieses Problem lösen würde mit Rx:

// A content control is a control that displays content.  That content can be
// anything at all like a string or another control.  Every content control contains
// another control: a ContentPresenter.  The ContentPresenter's job is to generate
// a visual representation of the Content property. For example, if the Content property
// of the ContentControl is a string, the ContentPresenter creates a TextBlock and inserts
// the string into it.  On the other hand if the Content property is another control the 
// ContentPresenter just inserts it into the visual tree directly.
public class MyContentControl : ContentControl
{
   // A subject implements both IObservable and IObserver.  When IObserver methods
   // are called, it forwards those calls to all of its listeners.
   // As a result it has roughly the same semantics as an event that we can "raise."
   private Subject<object> contentChanged = new Subject<object>();

   // This is a reference to the ContentPresenter in the ContentControl's template
   private ContentPresenter contentPresenter; 

   // This is a reference to the Image control within ContentControl's template.  It is displayed on top of the ContentPresenter and has a cool blur effect applied to it.
   private Image contentImageControl; 

   public MyContentControl()
   {
      // Using Rx we can create specific events from general events.
      // In this case I want to create a specific event ("contentImageChanged") which
      // gives me exactly the data I need to respond and update the UI.
      var contentImageChanged = 
         // get the content from the content changed event
         from content in contentChanged
         where content != null
         // Wait for the ContentPresenter's visual representation to update.
         // ContentPresenter is data bound to the Content property, so it will
         // update momentarily.
         from _ in contentPresenter.GetLayoutUpdated().Take(1)
         select new WritableBitmap(contentPresenter, new TranslateTransform());

      contentImageChanged.Subscribe(
         contentImage => 
         {
            // Hide the content presenter now that we've taken a screen shot              
            contentPresenter.Visibility = Visibility.Collapsed; 

            // Set the image source of the image control to the snapshot
            contentImageControl.ImageSource = contentImage;
         });
   }

   // This method is invoked when the Content property is changed.
   protected override OnContentChanged(object oldContent, object newContent)
   {
      // show the content presenter before taking screenshot
      contentPresenter.Visibility = Visibility.Visible;  

      // raise the content changed "event"
      contentChanged.OnNext(newContent);   

      base.OnContentChanged(oldContent, newContent);
   }
}

Dieses Beispiel ist besonders einfach, da es nur zwei aufeinanderfolgende Operationen Sequenz ist. Auch in diesem einfachen Beispiel wenn wir sehen, dass Rx-Wert hinzufügt. Ohne sie würde ich gebrauchte Zustandsvariablen zu haben, hatte die Ereignisse, um sicherzustellen, wurden in einer bestimmten Reihenfolge zu schießen. Ich hätte auch ein paar ziemlich hässlichen Code schreiben musste explizit von der Veranstaltung Layoutupdated zu lösen.

Wenn Sie mit Rx sind die Programmierung der Trick ist, denken: „Welche Veranstaltung will ich meinen Rahmen zur Verfügung gestellt?“ und dann gehen erstellen. Wir über Ereignisse so einfach, Input-driven Dinge ( „Mouseover“, „per Mausklick“, „keyup“, etc) zu denken, ausgebildet. Allerdings gibt es keinen Grund, Ereignisse, die nicht sehr komplex sein kann und speziell für Ihre Anwendung ( „GoogleMsdnMashupStockDataArrived“, „DragStarting“ und „ImageContentChanged“). Wenn Sie Ihre Programme auf diese Weise strukturieren (schaffen genau das Ereignis I müssen und dann , um sie reagieren, indem Status zu ändern) Sie werden feststellen, dass sie weniger Staat Fehler haben, werden mehr bestellt, und insgesamt mehr Selbst sind -describing.

Haben Sie es? :-)

Andere Tipps

Ich bin nicht sicher, ob die Vorteile, aber ich sehe die folgenden Unterschiede mit klassischen .NET-Ereignisse:

Fehlermeldungen

Klassische Ereignisse würden eine separate Veranstaltung für diesen benötigen oder eine EventArgs Klasse mit einer Error Eigenschaft, die überprüft werden muss.

end-of-Mitteilungen Mitteilung

Klassische Ereignisse würden eine separate Veranstaltung für diesen benötigen oder eine EventArgs-Klasse mit einer Final Eigenschaft, die überprüft werden muss.

Es ist nur eine Erweiterung des ereignisbasierten Programmiermodell. Sie schaffen etwas, das IObserver implementiert, und im Grunde sind Sie „hier ist, was ich, wenn etwas in der Sammlung Änderungen passieren soll“ sagen. Auf diese Weise ist es nur eine Standardisierung von dem, was haben wir alle mit Ereignissen gemacht haben.

Sie sind schieben es, wie es eine große Kehrtwendung ist im Vergleich mit dem IEnumerable Muster. IEnumerable ist "Pull", während IObservable ist "Push".

Der einzige Vorteil, den ich über gerade Ereignisse zu sehen ist, dass es sich um eine standardisierte Schnittstelle ist. Ich sehe eine große Überlappung mit ObservableCollection hier aber (und INotifyCollectionChanged). Vielleicht versuchen sie das PERL Motto mit .NET zu übernehmen. „Es gibt mehr als einen Weg, es zu tun“

Sie sollten auf jeden Fall sehen Rx Workshop: Observable im Vergleich zu Events Video- und die beiliegende Herausforderung

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top