假设
我会假设 textBoxChanged 是由类似的东西创建的:
var textBoxChanged = Observable.FromEventPattern(x, "TextChanged")
.Select(evt => ((TextBox)evt.Sender).Text);
使用 SelectMany 时防止竞争条件
from... from... 在 LINQ 理解中转换为 SelectMany,这就是您正在使用的。 Rx 足够聪明,可以将GetDataAsync(input) 返回的Task<List<DataRecord>> 转换为IObservable<List<DataRecord>>。
问题是您想阻止结果来自除最近提交的搜索请求之外的所有搜索请求。
为此,您可以利用TakeUntil。它具有以下签名:
public static IObservable<TSource> TakeUntil<TSource, TOther>(
this IObservable<TSource> source,
IObservable<TOther> other
)
它从源 observable 序列返回值,直到另一个 observable 序列产生值。
我们可以这样使用它:
var searchResults = from input in textBoxChanged
from results in GetDataAsync(input).ToObservable().TakeUntil(textBoxChanged)
select results;
这将阻止竞争条件,但也会订阅两次 textBoxChanged。
改用Switch
这是一种非常有用的模式,因此使用Switch() 运算符引入了另一种方法,该运算符也负责双重订阅。
不使用SelectMany,只需将输入直接投影到搜索查询中——这将给出IObservable<IObservable<List<DataRecord>>的返回类型,一个流的流。 Switch 会从一个流跳到另一个流,只返回最新的流。这相当于 SelectMany/TakeUntil 组合:
var searchResults = (from input in textBoxChanged
select GetSearchResults(input).ToObservable())
.Switch();
I highly suggest looking at the Rx Hands on Lab that explains this in much more detail.