Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Dispatcher.CurrentDispatcher导致ReactiveUI调用挂起_C#_Winforms_Dispatcher_Reactiveui - Fatal编程技术网

C# Dispatcher.CurrentDispatcher导致ReactiveUI调用挂起

C# Dispatcher.CurrentDispatcher导致ReactiveUI调用挂起,c#,winforms,dispatcher,reactiveui,C#,Winforms,Dispatcher,Reactiveui,在下面的示例中,对ReactiveCommand调用.Execute会挂起或创建死锁。为什么会发生这种情况,最好的避免方法是什么 此错误仅在调用Dispatcher.CurrentDispatcher时发生。很遗憾,在这个更大的项目中,显然答案是不打电话 我在项目中有nuget包reactiveui core和reactiveui winforms,都是v7.4.0。我正在用Resharper从Visual Studio运行nunit测试 该代码是一个NUnit测试夹具,请注意,TimeoutA

在下面的示例中,对ReactiveCommand调用.Execute会挂起或创建死锁。为什么会发生这种情况,最好的避免方法是什么

此错误仅在调用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");
        }
    }

    [Test, Order(3)]
    public async Task Test_CreateCommandWithThreadpoolScheduler()
    {
        //This line causes unwanted behaviour
        var x = Dispatcher.CurrentDispatcher;

        //THIS WORKS AGAIN (using ThreadpoolScheduler when creating ReactiveCommand)
        try
        {
            await TimeoutAfterAsync(
                CommandOnTaskpoolScheduler.Execute(),
                TimeSpan.FromSeconds(5),
                "after dispatcher creation, with thread pool");
        }
        catch (TimeoutException)
        {
            Assert.Fail("ThreadpoolScheduler case timed out (not expected)");
        }
    }

    private static async Task<TResult> TimeoutAfterAsync<TResult>(IObservable<TResult> observable,
        TimeSpan timeout,
        string context)
    {
        var task = observable .ToTask();
        var result = await Task.WhenAny(task, Task.Delay(timeout));
        if (result == task)
        {
            // Task completed within timeout.
            return task.GetAwaiter().GetResult();
        }
        else
        {
            // Task timed out.
            throw new TimeoutException(context);
        }
    }
}
Dispatcher.CurrentDispatcher很有趣;如果当前线程还没有调度程序,它会为当前线程创建一个调度程序!这会给单元测试带来问题,因为新的调度程序是为线程池线程创建的,它不是STA,也没有消息泵

理想的解决方案是不调用CurrentDispatcher。曾经如果必须使用SynchronizationContext将结果/进度/事件传递给UI线程,请使用await或IProgress。为这些抽象创建测试环境要容易得多


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

谢谢,最后我能够在测试中删除CurrentDispatcher