我想在五秒钟内每秒钟尝试一些东西,如果它们都为假则返回false,第一次为真则返回true。命令式地,它看起来像这样:
bool TryFiveTimes()
{
for (int i = 0; i < 5; i++)
{
if (Fn())
return true;
System.Threading.Thread.Sleep(1000);
}
return false;
}
我想用Rx来做这个,但是想不出一个简洁的方法。我当前的尝试是:
bool TryFiveTimes()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Take(5)
.Select(_ => Fn())
.Scan(false, (curr, prev) => curr || prev)
.Last();
}
这将给出正确的结果,但如果Fn()
在结束之前返回true,则不会提前返回。
对于您的实现只需使用.First()
方法而不是.Last()
static bool TryFiveTimes()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Take(5)
.Select(_ => Fn())
.Scan(false, (curr, prev) => curr || prev)
.FirstOrDefault(v => v);
}
static int counters = 0;
static bool Fn()
{
counters++;
Console.WriteLine(counters);
return counters > 2;
}
[EDIT]:添加代码,证明Fn
方法将只在第一次返回True
之前执行
同样,这里也不需要Scan()
,更短的版本是:
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Take(5)
.Select(_ => Fn())
.FirstOrDefault(v => v);
您可以尝试像这样使用Concat
和Return
:
bool TryFiveTimes()
{
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Take(5)
.Select(_ => Fn())
.Where(x => x)
.Concat(Observable.Return(false))
.First();
}