我正在尝试使用Rx + ReactiveUI来解决我的第一个任务,并且正在寻找解决任务的最佳实践,显示一个输入框,一旦用户开始输入就会显示建议。
根据以下代码示例,异步加载建议的最佳方法是什么?使用Subscribe
或使用Select Many
?或者有更好的方法来实现这两个目标吗?
this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
.Throttle(SuggestionThrottle, RxApp.MainThreadScheduler)
.Value()
.SelectMany(async s => await this.LoadSearchSuggestions(s)); // 1st Possibility
this.SearchTerms.Subscribe(this.LoadSearchSuggestions); // 2nd Possibility
答案 0 :(得分:14)
您必须以任何方式致电Subscribe
。
Rx中的查询使用延迟评估,这意味着仅定义查询不会启动它。延迟评估允许您通过有条件地应用运算符来构建查询,仅将查询定义一次并将其存储在字段中以供日后使用,或者在调用Subscribe
之前传递引用而不会产生任何副作用。
如果不调用Subscribe
,您的查询将保持无效状态。
Subscribe
通过将IObserver<T>
传递给观察者来激活查询,或者您可以使用其重载来提供OnNext
,OnError
和/或{{ 1}}处理程序,Rx将为您转换为OnCompleted
。收到查询通知的是IObserver<T>
。
IObserver<T>
的无参数重载在内部使用静默观察者,目的是仅为其副作用启动查询。例如,在您的情况下,如果您使用Subscribe
完成加载建议的所有工作而您不需要单独的SelectMany
,那么您可以通过调用无参数来启动查询过载IObserver<T>
。
在大多数情况下,您不应使用Subscribe
的无参数重载。 Subscribe
的要点是您传递给它的Subscribe
(或单个处理程序)旨在导致查询的副作用。通过仅在IObserver<T>
或Subscribe
运算符中引起副作用,查询更易于推理和维护。
但是,有一个相当常见的情况是使用Do
的无参数重载是有意义的:如果查询的副作用是由异步方法引起的,那么使用Subscribe
和无参数SelectMany
的重载最好。
原因很简单:Subscribe
是顺序组合运算符,它使您可以将异步方法作为查询中的顺序步骤调用。因此,SelectMany
将取消订阅与取消异步计算联系起来。处理订阅(由调用SelectMany
返回的IDisposble
表示)会导致Subscribe
运算符的特殊异步重载所提供的CancellationToken
被发出信号消除。您的异步方法可以监视SelectMany
以提前退出计算。
CancellationToken
没有任何重载接受异步观察者,Subscribe
返回OnNext
。但即使您在Task
处理程序中调用返回void的异步方法,也不会在处理订阅时发出异步方法的信号。
请注意,无论如何,您的两个代码示例都略有错误。第一个示例不需要OnNext
和async
关键字。如上所述,await
的特殊重载接受SelectMany
- 返回选择器函数,以及为该函数提供Task<T>
的其他重载。你可能应该使用后者。
你的第二个例子不应该编译,假设CancellationToken
返回LoadSearchSuggestions
。 (除非ReactiveUI库或您引用的其他库提供了Task
的重载,它接受Subscribe
- 返回函数,在这种情况下,您将不得不查阅其文档。)< / p>
除非后者,并假设您的其余查询是正确的,这是您应该做的:
Task
其中this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm)
.Throttle(SuggestionThrottle, RxApp.MainThreadScheduler)
.Value()
.SelectMany(LoadSearchSuggestionsAsync)
.Subscribe();
的定义如下:
LoadSearchSuggestionsAsync
请注意,Unit代表Rx中的 void 。这是必需的,因为返回非泛型async Task<Unit> LoadSearchSuggestionsAsync(string term, CancellationToken cancel)
{
...
return Unit.Default;
}
的异步方法不能与Task
一起使用。如果您要返回实际数据,则只需将SelectMany
替换为您的数据类型即可。然后,您还可以将Unit
处理程序传递给OnNext
并使用返回值执行某些操作,例如记录。