2014-12-23 63 views
3

我試圖解決我的第一個任務使用Rx + ReactiveUI,並尋找最佳實踐來解決任務,顯示一個輸入框,將顯示建議作爲用戶開始輸入即可。什麼是最好的方式來調用異步方法,使用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 

回答

12

您必須撥打Subscribe

Rx中的查詢使用延遲評估,這意味着僅定義查詢不會啓動它。懶惰評估允許您通過有條件地應用運算符來構建查詢,只定義一次查詢並將其存儲在字段中供以後使用,或者在調用Subscribe之前傳遞引用而不引起任何副作用。

沒有致電Subscribe您的查詢將保持不活動狀態。

Subscribe通過傳遞到您的觀察到激活IObserver<T>查詢,也可以使用它的過載,使您可以單獨提供OnNextOnError和/或OnCompleted處理器,其中的Rx轉換爲IObserver<T>你。接收查詢通知的是IObserver<T>

Subscribe有一個無參數超載,它在內部使用無聲觀察者,目的是僅爲其副作用開始查詢。例如,在您的情況下,如果您要使用SelectMany來完成加載建議的所有工作,並且您不需要單獨的IObserver<T>,則可以通過調用Subscribe的無參數超載來啓動查詢。

在大多數情況下,您不應使用Subscribe的無參數超載。 Subscribe的要點是,您傳遞給它的IObserver<T>(或單個處理程序)旨在引起查詢的副作用。通過僅在Subscribe或例如Do運算符中產生副作用,查詢更易於推理和維護。

但是,有一個相當常見的場景,其中使用的Subscribe的參數的過載是有道理的:如果查詢的副作用是通過異步方法造成的,那麼使用SelectManySubscribe的參超載一起是最好的。

原因很簡單:SelectMany是順序組合運算符,它使您能夠將異步方法作爲查詢中的順序步驟調用。因此,SelectMany將取消訂閱與取消異步計算綁定在一起。處理訂閱(由IDisposble表示,由呼叫返回到Subscribe)導致由SelectMany運營商的特殊異步過載提供的CancellationToken被標記爲取消。您的異步方法可以監視CancellationToken以儘早退出其計算。

Subscribe沒有任何接受異步觀察者的過載,OnNext返回Task。但即使您要在您的OnNext處理程序中調用無返回異步方法,也不會在訂閱處理時發送異步方法。

請注意,無論如何,你的兩個代碼示例都有點不對。第一個示例不需要關鍵字asyncawait。如上所述,有特殊的過載SelectMany接受一個Task<T>返回選擇器功能,並提供一個CancellationToken該功能的其他重載。你應該可以使用後者。

你的第二個例子不應該編譯,假設LoadSearchSuggestions返回Task。 (除非ReactiveUI庫或如果引用是提供接受Task -returning功能Subscribe過載一些其他圖書館,在這種情況下,你必須參考它們的文檔。)

除非後者,和假設您的查詢的其餘部分是正確的,這裏是你應該做的:

this.SearchTerms = this.ObservableForProperty(x => x.SearchTerm) 
    .Throttle(SuggestionThrottle, RxApp.MainThreadScheduler) 
    .Value() 
    .SelectMany(LoadSearchSuggestionsAsync) 
    .Subscribe(); 

其中LoadSearchSuggestionsAsync這樣定義:

async Task<Unit> LoadSearchSuggestionsAsync(string term, CancellationToken cancel) 
{ 
    ... 
    return Unit.Default; 
} 

注意Unit代表void in Rx。這是必需的,因爲返回非通用的異步方法Task不能與SelectMany一起使用。如果您有實際數據返回,則只需將Unit替換爲您的數據類型即可。然後,您還可以將OnNext處理程序傳遞給Subscribe,並對返回值執行一些操作,如日誌記錄。

+0

工程就像一個魅力。非常感謝您的詳細解答! – road242

+0

這是我見過很長時間裏最好的Rx相關答案之一。謝謝你增加我的理解。 –

相關問題