为什么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;
}
答案 0 :(得分:12)
RunAsync
和ToTask
都会产生 observable中的最后一个值。因此,在可观察的完成之前,不会产生任何值。但是用FromEventPattern
创建的可观察量通常不会完成。您需要强制它们完成Take
或Until
。
我还会注意到RunAsync
和ToTask
基本上是多余的,并且不需要同时执行这两项操作。
在您的情况下,我假设您真正对通过过滤器的第一个值感兴趣:
var task = Observable
.FromEventPattern<MessageResponseEventArgs>(communicator, "PushMessageRecieved")
.FirstAsync(i => i.EventArgs.GetRequestFromReceivedMessage().Name == requestName)
.Select(i => i.EventArgs)
.ToTask();
task.Wait();
答案 1 :(得分:2)
您正在观察的PushMessageRecieved
事件的处理程序需要在当前同步上下文中的UI线程上运行。在等待此任务时,您将阻止UI线程(表示当前上下文)。任务无法完成,因为您正在等待它,您永远不会等待它,因为它无法运行。死锁。
您不应该同步阻止任务,而是异步执行代码作为该任务的延续。