簡體   English   中英

Rx:如何以最小的樣板對內部可觀察的表面進行處理?

[英]Rx: How to perform an action on inner observable finish with minimum boilerplate?

為了簡化Rx,我正在編寫一個簡單的應用程序,該應用程序模仿讀取文件並支持取消。

它是這樣的:

  • 當用戶按下“運行”按鈕時,程序

    • 顯示忙碌指示器,
    • 逐塊讀取文件,這是一個漫長的過程,報告每個文件的長度,
    • 當讀取過程完成(或取消,請參見下文)時,隱藏忙碌指示器。
  • 如果用戶按下“取消”按鈕,則文件讀取過程將被取消。

  • 如果用戶在上一操作仍在進行時按下“運行”按鈕,則前一操作將被取消並開始新的操作。

我正在尋找一種使用最少的粘合代碼實現此目標的方法,同時仍然保持簡單的同步操作序列的外觀,在該序列中可以輕松看到自然的控制流程。

主要問題似乎是當內部可觀察到的(閱讀器)完成時隱藏忙碌指示器,外部可觀察到的是“運行”單擊事件序列。

到目前為止,我提出了程序主要部分的以下兩個版本:

基於訂閱者:

IObservable<byte[]> xs =
   runClick
   .Do((Action<EventPattern<EventArgs>>)(_ => ShowBusy(true)))
   .Do(_ => ShowError(false))
   .Select(_ =>
      reader
      .TakeUntil(cancelClick)
      .Publish(ob =>
      {
         ob.Subscribe(
            b => { },
            ex =>
            {
               Console.WriteLine("ERROR: " + ex);
               ShowBusy(false);
               ShowError(true);
            },
            () => ShowBusy(false));
         return ob;
      }))
   .Switch();
xs = xs.Catch<byte[], Exception>(e => xs);

並且基於concat:

IObservable<byte[]> xs =
   runClick
   .Do((Action<EventPattern<EventArgs>>)(_ => ShowBusy(true)))
   .Do(_ => ShowError(false))
   .Select(_ =>
      reader
      .TakeUntil(cancelClick)
      .DoAfter(() =>
         ShowBusy(false)))
   .Switch();
xs = xs.Catch<byte[], Exception>(e =>
{
   Console.WriteLine("ERROR: " + e);
   ShowBusy(false);
   ShowError(true);
   return xs;
});

使用一種自定義方法DoAfter

public static IObservable<T> DoAfter<T>(this IObservable<T> observable, Action action)
{
   IObservable<T> appended = observable.Concat(
      Observable.Create<T>(o =>
      {
         try
         {
            action();
         }
         catch (Exception ex)
         {
            o.OnError(ex);
            return Disposable.Empty;
         }

         o.OnCompleted();
         return Disposable.Empty;
      }));
   return appended;
}

(請參閱此處的整個應用程序代碼)。

兩種實現方式都不能完全滿足我的要求:第一種方法很冗長,第二種方法則迫使我編寫自己的方法來完成一項相當簡單的任務,我希望該任務可以用標准方法涵蓋。 我想念什么嗎?

原來我缺少的是Do方法的重載 我可以使用它代替我的自定義DoAfter方法,然后代碼看起來不錯。

IObservable<byte[]> xs =
   runClick
   .Do((Action<EventPattern<EventArgs>>)(_ => ShowBusy(true)))
   .Do(_ => ShowError(false))
   .Select(_ =>
      reader
      .TakeUntil(cancelClick)
      .Do(
         b => { },
         ex =>
         {
            Console.WriteLine("ERROR: " + ex);
            ShowBusy(false);
            ShowError(true);
         },
         () => ShowBusy(false)
      ))
   .Switch();
xs = xs.Catch<byte[], Exception>(e => xs);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM