为了账号安全,请及时绑定邮箱和手机立即绑定

Dispatcher.CurrentDispatcher 导致 ReactiveUI 调用挂起

Dispatcher.CurrentDispatcher 导致 ReactiveUI 调用挂起

C#
猛跑小猪 2022-10-15 14:26:32
在下面的示例中,调用.Execute()ReactiveCommand 会挂起或创建死锁。为什么会发生这种情况,避免这种情况的最佳方法是什么?该错误仅在调用 Dispatcher.CurrentDispatcher 时发生。不幸的是,不称其为显而易见的答案在更大的项目中不是一个选择。我在项目中有nuget包reactiveui-core和reactiveui-winforms,都是v7.4.0。我正在使用 Resharper 从 Visual Studio 运行 nunit 测试。该代码是一个 NUnit 测试夹具,注意 TimeoutAfterAsync 是一个帮助方法,用于在一定超时后取消测试,在没有这个包装器的情况下观察到行为[TestFixture]public class ReactiveCommandTests{    private static async Task<bool> ExecuteCommand()    {        await Task.Delay(1000);        return true;    }    public static ReactiveCommand<Unit, bool> Command = ReactiveCommand.CreateFromTask(ExecuteCommand);    public static ReactiveCommand<Unit, bool> CommandOnTaskpoolScheduler = ReactiveCommand.CreateFromTask(ExecuteCommand, outputScheduler: RxApp.TaskpoolScheduler);    public static ReactiveCommand<Unit, bool> CommandAfterDispatcherInvoked = ReactiveCommand.CreateFromTask(ExecuteCommand);    [Test, Order(1)]    public async Task Test()    {        //THIS WORKS        try        {            await TimeoutAfterAsync(                Command.Execute(),                TimeSpan.FromSeconds(5),                "control");        }        catch (TimeoutException)        {            Assert.Fail("Control case timed out (not expected)");        }    }    [Test, Order(2)]    public async Task Test_CreateCommandAfterDispatcherCall()    {        //This line causes unwanted behaviour        var x = Dispatcher.CurrentDispatcher;        //THIS FAILS        try        {            await TimeoutAfterAsync(                CommandAfterDispatcherInvoked.Execute(),                TimeSpan.FromSeconds(5),                "after dispatcher creation");        }        catch (TimeoutException)        {            Assert.Fail("Executing commandAfterDispatcherInvoked timed out (expected, but not understood");        }    }
查看完整描述

1 回答

?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

Dispatcher.CurrentDispatcher很有趣;如果当前线程还没有调度器,它会为当前线程创建一个调度器!这会导致单元测试出现问题,因为新的调度程序是为线程池线程创建的,该线程不是 STA 并且没有消息泵。

理想的解决方案是不调用CurrentDispatcher. 曾经。使用awaitorIProgress<T>或(如果必须)SynchronizationContext将结果/进度/事件传达给 UI 线程。这些抽象更容易为其创建测试环境。

但就目前而言,您可能可以使用WpfContext,这是 Async CTP 早期版本中包含的一种旧实用程序类型。WpfContext.Run将接受一个委托,为当前线程创建一个调度程序上下文,并在该调度程序上下文中执行该委托,泵送其消息,直到异步操作完成。


查看完整回答
反对 回复 2022-10-15
  • 1 回答
  • 0 关注
  • 77 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信