[英]Observable.Interval restarts for each subscription
我第一次定義測量時間表的嘗試是:
var schedule = Observable.Concat(
Observable.Interval(TimeSpan.FromSeconds(1)).Take(3),
Observable.Interval(TimeSpan.FromSeconds(3)).Take(3),
Observable.Interval(TimeSpan.FromSeconds(5)));
不幸的是,當取消訂閱和重新訂閱時,它會重新啟動,這對我而言不是理想的行為。 因此,我想到了這樣的東西:
class Schedule : IObservable<DateTime>, IDisposable
{
readonly ISubject<DateTime> _subject;
readonly IDisposable _subscrption;
public Schedule()
{
_subject = new BehaviorSubject<DateTime>(DateTime.UtcNow);
_subscrption = Observable.Concat(
Observable.Interval(TimeSpan.FromSeconds(1)).Take(3),
Observable.Interval(TimeSpan.FromSeconds(3)).Take(3),
Observable.Interval(TimeSpan.FromSeconds(5)))
.Select(i => DateTime.UtcNow)
.Subscribe(_subject);
}
public IDisposable Subscribe(IObserver<DateTime> observer)
{
return _subject.Subscribe(observer);
}
public void Dispose()
{
_subscrption.Dispose();
}
}
它可以工作,但需要在使用后進行處理。 有什么簡單的方法可以定義Schedule而不暴露IDisposable?
如果您要取消所有觀察者的訂閱,然后重新訂閱,則真的沒有辦法讓Disposable
保持跟蹤連接。 因為您的Observable不會直接知道最新的取消訂閱是否真的是最后一個。
我建議使用“ Generate
而不是“連接可觀察對象”
IConnectableObservable<DateTime> source = Observable.Generate(
0,
_ => true,
x => x + 1,
x => DateTime.UtcNow,
x => {
if (x < 3) return TimeSpan.FromSeconds(1);
else if (x < 5) return TimeSpan.FromSeconds(3);
else return TimeSpan.FromSeconds(5);
}).Publish();
Publish
將您的Observable變為ConnectableObservable,並為您提供兩個選項來管理源何時實際產生事件。
//1) Explicit connect
IDisposable connection = source.Connect();
//2) RefCounted connection
IObservable<DateTime> rcSource = source.RefCount();
在第一個版本中,一旦連接,源將變為“熱”狀態;當您要斷開連接時,應丟棄連接。
在第二個中,當沒有更多觀察者時,源將自動斷開連接。
另請參閱熱與冷可觀察物
這是我定義的不需要處理的解決方案。 不過,這非常復雜,因此,如果可以使用Rx工具簡化某些操作,我將不勝感激。
用法:
IObservable<DateTime> schedule = new Schedule()
.Setup(TimeSpan.FromSeconds(1), 3)
.Setup(TimeSpan.FromSeconds(3), 3)
.Setup(TimeSpan.FromSeconds(5));
時間表在哪里:
class Schedule : IObservable<DateTime>
{
readonly TimeSpan TimerPrecision = TimeSpan.FromMilliseconds(1);
readonly IEnumerable<TimeSpan> Intervals;
readonly IEnumerator<DateTime> Event;
public Schedule()
: this(new TimeSpan[0])
{
}
Schedule(IEnumerable<TimeSpan> intervals)
{
Intervals = intervals;
Event = Start();
Event.MoveNext();
}
public Schedule Setup(TimeSpan interval)
{
return Setup(interval, Int32.MaxValue);
}
public Schedule Setup(TimeSpan interval, int repeat)
{
return new Schedule(
Intervals.Concat(
Enumerable.Repeat(interval, repeat)));
}
public IDisposable Subscribe(IObserver<DateTime> observer)
{
var timer = new System.Timers.Timer() { AutoReset = true };
timer.Elapsed += (s, a) =>
{
observer.OnNext(DateTime.UtcNow);
if (!TryArm(timer))
observer.OnCompleted();
};
if (!TryArm(timer))
observer.OnCompleted();
return timer;
}
IEnumerator<DateTime> Start()
{
var time = DateTime.UtcNow;
yield return time;
foreach (var interval in Intervals)
{
time += interval;
yield return time;
}
}
TimeSpan Delay()
{
var now = DateTime.UtcNow;
lock (Event)
while (Event.Current - DateTime.UtcNow < TimerPrecision)
Event.MoveNext();
return Event.Current - now;
}
bool TryArm(System.Timers.Timer timer)
{
try
{
timer.Interval = Delay().TotalMilliseconds;
timer.Start();
return true;
}
catch(ObjectDisposedException)
{
return false;
}
catch(InvalidOperationException)
{
return false;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.