7

従来のライブ検索の例:

var searchResults = from input in textBoxChanged
                    from results in GetDataAsync(input)
                    select results;

GetDataAsync は次を返します。

 Task<List<DataRecord>>

これは明らかに競合状態であるため、2 番目の入力によってトリガーされた検索が最初の入力の前に返された場合、最初の入力の結果が後に来るため、間違ったデータが返されます。

私は .Switch() 演算子が魔法のようにこれを解決することをどこでも読み続けていますが、どのように?

.Switch() は以下にのみ存在します:

 IObservable<IObservable<T>>
4

1 に答える 1

16

予測

textBoxChanged が次のようなものによって作成されたと仮定します。

var textBoxChanged = Observable.FromEventPattern(x, "TextChanged")
                               .Select(evt => ((TextBox)evt.Sender).Text);

SelectMany 使用時の競合状態の防止

from... from... LINQ 内包表記は、SelectMany使用しているものである に変換されます。Task<List<DataRecord>>Rx は、返されたを にGetDataAsync(input)変換するほどスマートIObservable<List<DataRecord>>です。

問題は、最後に送信された検索要求以外の結果が返されないようにしたいということです。

これを行うには、を活用できますTakeUntil。次の署名があります。

public static IObservable<TSource> TakeUntil<TSource, TOther>(
    this IObservable<TSource> source,
    IObservable<TOther> other
)

そして、他のオブザーバブル シーケンスが値を生成するまで、ソース オブザーバブル シーケンスから値を返します。

次のように使用できます。

var searchResults = from input in textBoxChanged
                    from results in GetDataAsync(input).ToObservable().TakeUntil(textBoxChanged)
                    select results;

これにより、競合状態が回避されますが、textBoxChanged に 2 回登録されます。

Switch代わりに使用する

Switch()二重サブスクリプションも処理するオペレーターを使用して別のアプローチが導入されたのは非常に便利なパターンです。

を使用する代わりにSelectMany、入力を検索クエリに直接射影するだけです。これIObservable<IObservable<List<DataRecord>>により、ストリームのストリームである の戻り値の型が得られます。Switch はストリームからストリームへとジャンプし、最新のストリームのみを返します。これは、SelectMany/TakeUntil コンボと同等です。

var searchResults = (from input in textBoxChanged
                     select GetSearchResults(input).ToObservable())
                    .Switch();

これについて詳しく説明している Rx ハンズオン ラボを参照することを強くお勧めします。

于 2013-11-03T15:20:48.443 に答える