クラシックイベントに対する.NET Rxの利点は?
-
06-07-2019 - |
質問
.NET 4.0 beta 2 には IObservable および IObserver インターフェース。
従来の.NETイベントと比較した場合の利点は何ですか?これは同じ問題を解決しませんか?
解決
IObservableをイベントとして使用して、イベントをタイプIObservableのプロパティで公開するコードを置き換えることができますが、それは実際にはポイントではありません。
IObservableについて理解する必要がある2つの重要なことがあります:
-
これまで統合方法がわからなかった2つの概念を統合します:非同期操作(通常は単一の値を返す)とイベント(通常は永遠に続く)
-
構成可能。 CLRイベント、IAsyncResult、またはINotifyCollectionChangedとは異なり、一般的なイベントと非同期操作から特定のイベントを構築できます。
今日の午後、職場で出会った例です。
Silverlightには、通常のコントロールには適用できない画像コントロールに適用できる効果がいくつかあります。コントロールのコンテンツが変更されたときにこれらの制限を回避するには、視覚的な外観が更新されるのを待って、スクリーンショットを撮ります。次に、視覚表現を非表示にし、スナップショットに置き換えて、視覚効果を画像に適用します。これで、画像効果をコントロールに適用できます(インタラクティブではないと仮定します)。
このプログラムは簡単ですが、非同期である必要があるためです。画像にエフェクトを適用する前に、2つの連続した非同期操作が完了するまで待機する必要があります。
- コントロールのコンテンツが変更されました
- コントロールの外観が更新されます
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);
}
}
この例は、連続する操作が2つしかないため、特に単純です。この単純な例でも、Rxが価値を追加することがわかります。それがなければ、イベントが特定の順序で発生するように状態変数を使用する必要がありました。また、LayoutUpdatedイベントから明示的に切り離すために、かなりいコードを記述する必要がありました。
Rxでプログラミングしているときの秘frameworkは、「フレームワークの提供を希望するイベントは何ですか」と考えることです。作成します。私たちは、イベントを単純な入力主導のもの(「マウスオーバー」、「マウスクリック」、「キーアップ」など)として考えるように訓練されています。ただし、イベントが非常に複雑でアプリに固有でない理由はありません(&quot; GoogleMsdnMashupStockDataArrived&quot;、&quot; DragStarting&quot;、&quot; ImageContentChanged&quot;)。プログラムをこのように構成すると(必要なイベントを正確に作成してから状態を変更して応答する)、状態のバグが少なくなり、順序が整い、全体としてより自己になります。 -説明。
わかった? :-)
他のヒント
利点はわかりませんが、従来の.NETイベントには次のような違いがあります。
エラー通知
クラシックイベントには、このための個別のイベント、またはチェックが必要な Error
プロパティを持つ EventArgs
クラスが必要です。
通知終了通知
クラシックイベントでは、このイベントまたはチェックが必要な Final
プロパティを持つ EventArgs
クラスの別のイベントが必要になります。
これは、イベントベースのプログラミングモデルの単なる拡張機能です。 IObserverを実装するものを作成します。基本的には、「コレクション内の何かが変更されたときに私が何をしたいのか」と言っています。そのように、これは私たち全員がイベントで行ってきたことの標準化にすぎません。
IEnumerableパターンと比較して、大きな顔のようにプッシュします。 IEnumerableは「pull」ですが、IObservableは「push」です。
単純なイベントよりも優れているのは、標準化されたインターフェイスであることです。ただし、ObservableCollectionと大きな重複が見られます(およびINotifyCollectionChanged)。たぶん、彼らは.NETでPERLのモットーを採用しようとしています。「それを行う方法は複数あります」。
Rx Workshop:Observable vs Events ビデオと 添付のチャレンジを完了