c# - 为什么这个 Cancellation Disposable 永远不会在 Observable.Dispose() 上被取消?

标签 c# .net windows system.reactive

我正在 WinForms 应用程序中使用 RxFramework。我尝试运行 Observable 异步并使用 CancellationDisposable 在用户单击按钮时取消操作。但它不起作用!

假设我有一个带有 2 个按钮和一个进度栏的表单。 Button1_click 订阅新线程上的观察者。然后立即按下 Button2_click 以取消操作。 为什么 cancel.Token.IsCancellationRequested 永远不会为真?

private IDisposable obs = null;
private void button1_Click(object sender, EventArgs e) {
    var countObserver = Observable.Create<int>(observer => {
        var cancel = new CancellationDisposable();

        if (!cancel.Token.IsCancellationRequested) {
            //Step 1 of a long running process using lot of resources...
            observer.OnNext(1);
        }
        if (!cancel.Token.IsCancellationRequested) {
            //Step 2 of a long running process using lot of resources...
            observer.OnNext(1);
        }
        if (!cancel.Token.IsCancellationRequested) {
            //Step 3 of a long running process using lot of resources...
            observer.OnNext(1);
        }
        observer.OnCompleted();

        return cancel;
    });

    obs = countObserver
        .ObserveOn(new ControlScheduler(this))
        .SubscribeOn(Scheduler.ThreadPool)
        .Subscribe(i => {
            //Update a progress bar here...
        });

}

private void button2_Click(object sender, EventArgs e) {
    if (obs != null)
        obs.Dispose();
}

最佳答案

之所以会发生这种情况,是因为您传递给 Observable.Create 的 lambda 不会返回 CancellationDisposable 直到它完成所有步骤。因此,操作顺序如下:

  1. 您调用订阅
  2. UI 线程阻塞
  3. ThreadPool 线程上,执行进入 lambda
  4. CancellationDisposable 已创建
  5. 您多次检查取消情况并执行整个过程。在此期间,您的进度条会更新。
  6. cancel 由 lambda 返回
  7. UI 线程被释放,obs 获取其值
  8. 您单击 Button2 并调用 obs.Dispose
  9. cancel 获取 cancel.Token.IsCancellationRequested=true。但什么也没有发生,因为一切都已经发生了。

这是固定代码:

private void button1_Click(object sender, EventArgs e) {
  var countObserver = Observable.Create<int>(observer => {
    var cancel = new CancellationDisposable();

    // Here's the magic: schedule the job in background and return quickly
    var scheduledItem = Scheduler.ThreadPool.Schedule(() =>
    {
      if (!cancel.Token.IsCancellationRequested) {
        //Step 1 of a long running process using lot of resources...
        observer.OnNext(1);
      }
      if (!cancel.Token.IsCancellationRequested) {
        //Step 2 of a long running process using lot of resources...
        observer.OnNext(1);
      }
      if (!cancel.Token.IsCancellationRequested) {
        //Step 3 of a long running process using lot of resources...
        observer.OnNext(1);
      }
      observer.OnCompleted();
    });

    return new CompositeDisposable(cancel, scheduledItem);
});

obs = countObserver
    .ObserveOn(new ControlScheduler(this))
    .Subscribe(i => {
        //Update a progress bar here...
    });

}

关于c# - 为什么这个 Cancellation Disposable 永远不会在 Observable.Dispose() 上被取消?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8172235/

相关文章:

c# - 调用 RPG 程序的 iSeries 存储过程不向程序返回值

c# - 如何在使用 Newtonsoft.Json 序列化 json 时忽略默认值

windows - 为什么 EM_SETMARGINS 在 Windows 7 下不起作用?

c++ - Ctrl Z 的实际工作原理

c# - 小于和大于需要在 C# 正则表达式中转义吗?

c# - 在 MVC 的每个页面上放置重复出现的代码的正确位置是什么

c# - 如何使用 NHibernate 复制对象

c# - 如何防止创建的线程多于可用的硬件线程数?

java - LINQ Join 的 Java 8 Stream API 等效项是什么?

windows - 为什么 Start/Wait 在与 URL 一起使用时不等待?