IObservable<T>。ToTask<T> 方法返回等待激活的任务



为什么task会永远等待?:

var task = Observable
    .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved")
    .Where(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName)
    .Select(i => i.EventArgs)
    .RunAsync(System.Threading.CancellationToken.None)
    .ToTask();
task.Wait();

我知道"PushMessageRecieved"被解雇了;我可以在Select lambda上设置一个断点并点击它。但task.Wait()永远不会移动。

更好的更新:FirstAsync()是我想要的:

    public static Task<MessageResponseEventArgs> HandlePushMessageRecievedAsync(this ICommunicator communicator, RequestName requestName)
    {
        if (communicator == null) return Task.FromResult<MessageResponseEventArgs>(null);
        var observable = GetCommunicatorObservableForPushMessageReceived(communicator);
        return observable
            .Where(i => i.GetRequestFromReceivedMessage().Name == requestName)
            .Select(i => i)
            .FirstAsync()
            .ToTask();
    }

其中GetCommunicatorObservableForPushMessageReceived()为:

    static IObservable<MessageResponseEventArgs> GetCommunicatorObservableForPushMessageReceived(ICommunicator communicator)
    {
        if (communicatorObservableForPushMessageReceived == null)
        {
            communicatorObservableForPushMessageReceived = Observable
                .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved")
                .Where(i => !IsPreviousMessage(i.EventArgs.GetRequestFromReceivedMessage().EventId))
                .Select(i => i.EventArgs);
        }
        return communicatorObservableForPushMessageReceived;
    }

更新:有点可怕的是(但它有效):

public static Task<MessageResponseEventArgs> HandlePushMessageRecievedAsync(this ICommunicator communicator, RequestName requestName)
{
    if (communicator == null) return Task.FromResult<MessageResponseEventArgs>(null);
    var completionSource = new TaskCompletionSource<MessageResponseEventArgs>();
    Observable
        .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved")
        .Where(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName)
        .Select(i => i.EventArgs)
        .ToEvent().OnNext += (args) =>
        {
            if (args.Response.Errors != null && args.Response.Errors.Any())
            {
                completionSource.TrySetException(args.Response.Errors.Select(j => new Exception(j.ErrorMessage)));
            }
            else
            {
                completionSource.TrySetResult(args);
            }
        };
    return completionSource.Task;
}

RunAsyncToTask都产生可观测值中的最后一个值。因此,在可观察完成之前,不会产生任何值。但是用FromEventPattern创建的可观察性通常并不完整。你需要强迫他们完成TakeUntil之类的东西。

我还将注意到RunAsyncToTask本质上是冗余的,不需要同时做这两件事。

在您的情况下,我假设您真的对通过过滤器的第一个值感兴趣:

var task = Observable
    .FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved")
    .FirstAsync(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName)
    .Select(i => i.EventArgs)
    .ToTask();
task.Wait();

您观察到的PushMessageRecieved事件的处理程序需要在当前同步上下文中的UI线程上运行。在等待此任务时,您正在阻塞UI线程(表示当前上下文)。任务无法完成是因为您在等待它,您永远无法完成等待是因为它无法运行。僵局

您不应该同步阻塞任务,而应该异步执行代码作为该任务的延续。

相关内容

  • 没有找到相关文章