C# 4.0 ObserveOn(Scheduler.CurrentThread)不';t使订阅的操作在原始线程上运行

C# 4.0 ObserveOn(Scheduler.CurrentThread)不';t使订阅的操作在原始线程上运行,c#-4.0,system.reactive,C# 4.0,System.reactive,我有一个执行回调的操作,它将在完成后使用泛型参数调用,即操作。我想在操作开始时显示一个繁忙的微调器,然后在调用回调时将其移除,因此我创建了一个简单的实用程序来实现这一点。我遇到的问题是,用户希望他们的回调在原始调用线程上运行,但并不总是这样。它几乎总是在单元测试(nUnit)中完美工作,但在应用程序实际运行时(WPF、.Net 4)对某些调用不起作用 以下是我所拥有的相关信息 void WrapAsyncCallbackPattern<T>(Action<T> callb

我有一个执行回调的操作,它将在完成后使用泛型参数调用,即
操作
。我想在操作开始时显示一个繁忙的微调器,然后在调用回调时将其移除,因此我创建了一个简单的实用程序来实现这一点。我遇到的问题是,用户希望他们的回调在原始调用线程上运行,但并不总是这样。它几乎总是在单元测试(nUnit)中完美工作,但在应用程序实际运行时(WPF、.Net 4)对某些调用不起作用

以下是我所拥有的相关信息

void WrapAsyncCallbackPattern<T>(Action<T> callback, Action<Action<T>> actionToRun)
{
    var subject = new AsyncSubject<T>();
    try
    {
        actionToRun(
            result =>
            {
                subject.OnNext(result);
                subject.OnCompleted();
            });
    }
    catch (Exception ex)
    {
        subject.OnError(ex);
    }

    subject
        .ObserveOn(Scheduler.CurrentThread)
        .Subscribe(callback, OnError);
}

您可能对调度器.CurrentThread的功能有错误的理解。我认为每个人都会犯这个错误

CurrentThread
调度程序与执行的可观察对象相关,而不是在定义(或订阅)时。考虑延迟或延迟执行。这应该是有意义的,因为无论何时跳转到不同的线程,您都需要某种方法来编组调用

所以你真正想要的是这样的东西:

var synchContext = new SynchronizationContextScheduler(
    System.Threading.SynchronizationContext.Current) 

subject
    .ObserveOn(synchContext)
    .Subscribe(callback, OnError);
或者可能:

subject
    .ObserveOn(this) /* this is my current form */
    .Subscribe(callback, OnError);
如果您这样做,您应该能够控制在哪个线程上运行回调


您的测试可能成功了,因为它们最终是同步执行的。

您可能对调度器.CurrentThread的功能有错误的理解。我认为每个人都会犯这个错误

CurrentThread
调度程序与执行的可观察对象相关,而不是在定义(或订阅)时。考虑延迟或延迟执行。这应该是有意义的,因为无论何时跳转到不同的线程,您都需要某种方法来编组调用

所以你真正想要的是这样的东西:

var synchContext = new SynchronizationContextScheduler(
    System.Threading.SynchronizationContext.Current) 

subject
    .ObserveOn(synchContext)
    .Subscribe(callback, OnError);
或者可能:

subject
    .ObserveOn(this) /* this is my current form */
    .Subscribe(callback, OnError);
如果您这样做,您应该能够控制在哪个线程上运行回调


您的测试可能成功了,因为它们最终是同步执行的。

单元测试实际上是为了验证它们是否在不同的线程上运行,作为最后断言的一部分。如果测试结果不正确,那么测试结果几乎是无效的。有趣的是,这个更改在应用程序运行时修复了它,但是现在测试失败了,调用线程、操作线程和回调线程都不同了。如果您有任何想法,我将添加我的测试代码。@BryanAnderson-您发布的测试代码中没有Rx。你发布了正确的测试方法吗?是的,我更新了我的方法以显示签名,所以它更清晰。在背景操作课上。Rx是类/函数的一种实现细节,因此它对使用者是隐藏的(因此是测试)。单元测试实际上是为了验证它们是否在不同的线程上运行,作为最后断言的一部分。如果测试结果不正确,那么测试结果几乎是无效的。有趣的是,这个更改在应用程序运行时修复了它,但是现在测试失败了,调用线程、操作线程和回调线程都不同了。如果您有任何想法,我将添加我的测试代码。@BryanAnderson-您发布的测试代码中没有Rx。你发布了正确的测试方法吗?是的,我更新了我的方法以显示签名,所以它更清晰。在背景操作课上。Rx是类/函数的一种实现细节,因此它对消费者是隐藏的(因此是测试)。