[英]Rx: Wait for first item for a period of time
I would like to transform my legacy event-based method to observable based, but I am quite new to Rx, so I am stuck now.我想将我遗留的基于事件的方法转换为基于可观察的方法,但我对 Rx 很陌生,所以我现在被困住了。
I have an event source, which is an observable by now.我有一个事件源,它现在是可观察的。 At a certain point in time, I have to start a method that ends either by returning the next element in the line or null if it is timed out.
在某个时间点,我必须启动一个方法,该方法通过返回行中的下一个元素或 null(如果超时)来结束。
The event-based approach looks like this:基于事件的方法如下所示:
public async Task<ReaderEvent> WaitForReaderAsync(int PlaceId, TimeSpan waitFor)
{
ReaderEvent result = null;
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(new [] { topLevelToken }))
{
cts.CancelAfter(waitFor);
EventHandler<ReaderEvent> localHandler = (o, e) =>
{
if (e.PlaceId == PlaceId)
{
result = e;
cts.Cancel();
}
};
ReaderEventHandler += localHandler;
try
{
await Task.Delay(waitFor, cts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
//...
}
ReaderEventHandler -= localHandler;
}
return result;
}
As you can see, the idea is that the delay is cancelled either by the arrival of the event I am waiting for or the token source is cancelled by configuration after that specific amount of time.正如您所看到的,这个想法是延迟被我正在等待的事件的到达取消,或者令牌源在特定时间后被配置取消。 Quite clean.
很干净。
Now, the Rx version:现在,Rx 版本:
public async Task<ReaderEvent> WaitForReaderAsync(int PlaceId, TimeSpan waitFor)
{
ReaderEvent result = null;
var observable = _OnReaderEvent.FirstAsync(r => r.PlaceId == PlaceId);
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(new [] { topLevelToken }))
{
cts.CancelAfter(waitFor);
using (observable.Subscribe(x => {
result = x;
cts.Cancel();
{
try
{
await Task.Delay(waitFor, cts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException) { }
}
}
return result;
}
Not so clean... even worse... I have tried with Timeout extension too.不那么干净......更糟......我也尝试过超时扩展。 But as this is a one-shot subscribtion, I still need waiting somehow before I dispose the subscription.
但由于这是一次性订阅,我仍然需要等待才能处理订阅。 The only difference would be that the OnError would cancel the local token, not the built-in mechanism of CancelAfter.
唯一的区别是 OnError 将取消本地令牌,而不是 CancelAfter 的内置机制。
Is there any batter / more concise (more relying on Rx) way to do this?是否有任何击球手/更简洁(更依赖于 Rx)的方法来做到这一点?
Thank you!谢谢!
you could try with:你可以尝试:
var values = await _OnReaderEvent
.Where(r => r.PlaceId == placeId)
.Buffer(waitFor, 1)
.FirstAsync(); // get list of matching elements during waitFor time
return values.FirstOrDefault(); // return first element or null if the list is empty
Why not just go with a simple Rx version of the code:为什么不使用简单的 Rx 版本的代码:
public async Task<ReaderEvent> WaitForReaderAsync(int PlaceId, TimeSpan waitFor)
{
return await
_OnReaderEvent
.Where(r => r.PlaceId == PlaceId)
.Buffer(waitFor, 1)
.Select(xs => xs.FirstOrDefault())
.FirstOrDefaultAsync()
.ToTask();
}
This problem can be solved in lots of different ways.这个问题可以通过很多不同的方式来解决。 Here is one, utilizing the
Amb
, Return
, Delay
and FirstAsync
operators:这是一个,使用
Amb
、 Return
、 Delay
和FirstAsync
运算符:
public Task<ReaderEvent> WaitForReaderAsync(int PlaceId, TimeSpan waitFor)
{
return _OnReaderEvent
.Where(r => r.PlaceId == PlaceId)
.Amb(Observable.Return(default(ReaderEvent)).Delay(waitFor))
.FirstAsync()
.ToTask();
}
In the abnormal case that the _OnReaderEvent
observable is completed or completes during the waiting, the resulting Task
will transition to a faulted state, with the exception being InvalidOperationException
"Sequence contains no elements".在
_OnReaderEvent
observable 在等待期间完成或完成的异常情况下,生成的Task
将转换为错误状态,异常为InvalidOperationException
"Sequence contains no elements"。
Another implementation, functionaly equivalent to the previous one, using the Timeout
operator:另一种实现,在功能上等同于前一个,使用
Timeout
操作符:
public Task<ReaderEvent> WaitForReaderAsync(int PlaceId, TimeSpan waitFor)
{
return _OnReaderEvent
.Where(r => r.PlaceId == PlaceId)
.FirstAsync()
.Timeout(waitFor, Observable.Return(default(ReaderEvent)))
.ToTask();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.