2

昨日、Wes DyerがReactiveExtensions(Rx)を使用してドラッグ'n'ドロップを実装する方法を示す、最初のRxアプリケーションの作成(チャネル9)のスクリーンキャストを見ました。私がまだ理解していないこと:

スクリーンキャストの終わりに向かって、WesDyerは次のように入力します。

var q = from start in mouseDown
        from delta in mouseMove.StartsWith(start).Until(mouseUp)
                       .Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
                           new { X = cur.X - prev.X, Y = cur.Y - prev.Y }))
        select delta;

簡単に言うとq、マウスの移動座標デルタをサブスクライバーにプッシュするオブザーバブルです。

私が理解していないのは、どうすればうまくいくのかということですmm.Zip(mm.Skip(1), ...)!?

私の知る限り、IObservableそういう意味でIEnumerableは列挙できません。の「プル」の性質のおかげでIEnumerable、それは何度も何度も繰り返すことができ、常に同じアイテムを生み出します。(少なくとも、これはすべての正常に動作する列挙型に当てはまるはずIObservableです。)動作は異なります。アイテムは一度サブスクライバーにプッシュされ、それだけです。上記の例では、マウスの動きは単一のインシデントであり、メモリに記録されていないと繰り返すことができません。

では、彼らが取り組んでいるマウスイベントは単一の再現不可能なインシデントであるため、との組み合わせはどのように機能する.Zip可能性がありますか?この操作では、それを独立して2回「確認」.Skip(1)する必要はありませんか?mm


参考までに、次のメソッドシグネチャを使用しObservable.Zipます。

public static IObservable<TResult> Zip <TLeft, TRight, TResult>
(
    this IObservable<TLeft>       leftSource,     //  = mm
    IObservable<TRight>           rightSource,    //  = mm.Skip(1)
    Func<TLeft, TRight, TResult>  selector
)

PS:オペレーターには、非常に洞察に満ちた別のスクリーンキャストZipがあるのを見ました。

4

3 に答える 3

3

この操作では、mmを個別に2回「見る」必要はありませんか?

それは実際にあなたの質問の答えです:あなたは同じIObservableシーケンスを複数回サブスクライブすることができます。

mm.Skip(1)サブスクライブしmmて、最初の値を自身のサブスクライバーに非表示にします。mm.Skip(1)Zipはとの両方のサブスクライバーですmmmmよりも1つ多い値が生成されたため、Zipは、次の将来のmousemoveイベントで圧縮するために、常にmm.Skip(1)最後のmousemoveイベントを内部的にバッファリングします。mmセレクター関数は、両方の間のデルタを選択できます。

あなたが気付くべきもう一つのことは(あなたの質問のタイトルに対する本当の答えです)、これはObservable.FromEvent-ホットオブザーバブルであり、したがって再現性がないということです。しかし、Observable.Range(0,10)のように、実際には繰り返し可能なコールドObservableがあります。後者の場合、各サブスクライバーは、サブスクライバーごとに独立して生成されるため、同じ10個のイベントを受け取ります。mousemoveイベントの場合、これは当てはまりません(過去のマウス移動イベントは取得されません)。ただし、Zipは右と左のシーケンスを同時にサブスクライブするため、この場合は同じである可能性があります。IObservable

PS:ホット/繰り返し不可を作成することもできますIEnumerable:列挙子ごとに同じ値を返す必要はありません。たとえば、mousemoveイベントが発生するまで待機してからイベントを生成するIEnumerableを作成できます。この場合、列挙子は常にブロックします(悪い設計)が、それは可能です。;)

于 2010-09-04T18:24:41.907 に答える
2

あはは!PSで言及したZipスクリーンキャストは、重要な手がかりを与えてくれました。Zipアイテムが一方の観測量からもう一方の観測量よりも早く到着する可能性があるという事実を説明するために、アイテムを「覚えている」ということです。私は私の質問に答えようとします、私が間違っているなら誰かが私を訂正してくれることを願っています。

Zipこのような2つの観測可能なシーケンスからの入力をペアにします(文字と数字は「イベント」です)。

mm                        ----A---------B-------C------D-----------E----->
                              |         |       |      |           |
                              |         |       |      |           |
mm.Skip(1)                ----+---------1-------2------3-----------4----->
                              |         |       |      |           |
                              |         |       |      |           |
mm.Zip(mm.Skip(1), ...)   ----+--------A,1-----B,2----C,3---------D,4---->

そしてそれは確かに内部バッファリングをしなければなりません。私が投稿したコードでmmは、実際の「ライブ」で観察可能です。mm.Skip(1)それから派生したステートマシンのようなものです。Alex Pavenの回答は、これがどのように機能するかを簡単に説明しています。

したがって、mm.Zip(mm.Skip(1), ...)実際にはmm2回、1回は直接、もう1回はSkip(n)フィルターを通過します。また、オブザーバブルは繰り返し可能なシーケンスではないため、一方のシーケンスがもう一方のシーケンスよりも早くアイテムを生成するという事実を考慮して、内部バッファリングを実行します。

(私はすぐに.NET Reflectorを使用してRxソースを一瞥しましたが、実際にZipQueue。)

于 2010-09-03T11:43:04.693 に答える
1

アイテムは一度サブスクライバーにプッシュされ、それだけです。

はい、1つのアイテムが1回プッシュされますが、そのアイテムはイベントの「シーケンス」の1つです。シーケンスはまだシーケンスです。そのため、スキップが機能します。1つのアイテムをスキップし、次のアイテムが来ると、それを処理します(スキップしません)。

于 2010-09-03T11:10:26.267 に答える