VirtualTimeSchedulerBase<TAbsolute, TRelative>
public abstract class VirtualTimeSchedulerBase<TAbsolute, TRelative> : IScheduler, IServiceProvider, IStopwatchProvider where TAbsolute : IComparable<TAbsolute>
Base class for virtual time schedulers.
using System.Collections.Generic;
using System.Globalization;
namespace System.Reactive.Concurrency
{
public abstract class VirtualTimeSchedulerBase<TAbsolute, TRelative> : IScheduler, IServiceProvider, IStopwatchProvider where TAbsolute : IComparable<TAbsolute>
{
private sealed class VirtualTimeStopwatch : IStopwatch
{
private readonly Func<TimeSpan> _getElapsed;
public TimeSpan Elapsed => _getElapsed();
public VirtualTimeStopwatch(Func<TimeSpan> getElapsed)
{
_getElapsed = getElapsed;
}
}
public bool IsEnabled { get; set; }
protected IComparer<TAbsolute> Comparer { get; }
public TAbsolute Clock { get; set; }
public DateTimeOffset Now => ToDateTimeOffset(Clock);
protected VirtualTimeSchedulerBase()
: this(default(TAbsolute), (IComparer<TAbsolute>)Comparer<TAbsolute>.Default)
{
}
protected VirtualTimeSchedulerBase(TAbsolute initialClock, IComparer<TAbsolute> comparer)
{
Clock = initialClock;
if (comparer == null)
throw new ArgumentNullException("comparer");
Comparer = comparer;
}
protected abstract TAbsolute Add(TAbsolute absolute, TRelative relative);
protected abstract DateTimeOffset ToDateTimeOffset(TAbsolute absolute);
protected abstract TRelative ToRelative(TimeSpan timeSpan);
public abstract IDisposable ScheduleAbsolute<TState>(TState state, TAbsolute dueTime, Func<IScheduler, TState, IDisposable> action);
public IDisposable ScheduleRelative<TState>(TState state, TRelative dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException("action");
TAbsolute dueTime2 = this.Add(this.Clock, dueTime);
return ScheduleAbsolute(state, dueTime2, action);
}
public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException("action");
return ScheduleAbsolute(state, this.Clock, action);
}
public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException("action");
return ScheduleRelative(state, this.ToRelative(dueTime), action);
}
public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException("action");
return ScheduleRelative(state, this.ToRelative(dueTime - this.Now), action);
}
public void Start()
{
if (!IsEnabled) {
IsEnabled = true;
do {
IScheduledItem<TAbsolute> next = GetNext();
if (next != null) {
if (Comparer.Compare(next.DueTime, Clock) > 0)
Clock = next.DueTime;
next.Invoke();
} else
IsEnabled = false;
} while (IsEnabled);
}
}
public void Stop()
{
IsEnabled = false;
}
public void AdvanceTo(TAbsolute time)
{
int num = Comparer.Compare(time, Clock);
if (num < 0)
throw new ArgumentOutOfRangeException("time");
if (num != 0) {
if (IsEnabled)
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.CANT_ADVANCE_WHILE_RUNNING, "AdvanceTo"));
IsEnabled = true;
do {
IScheduledItem<TAbsolute> next = GetNext();
if (next != null && Comparer.Compare(next.DueTime, time) <= 0) {
if (Comparer.Compare(next.DueTime, Clock) > 0)
Clock = next.DueTime;
next.Invoke();
} else
IsEnabled = false;
} while (IsEnabled);
Clock = time;
}
}
public void AdvanceBy(TRelative time)
{
TAbsolute val = Add(Clock, time);
int num = Comparer.Compare(val, Clock);
if (num < 0)
throw new ArgumentOutOfRangeException("time");
if (num != 0) {
if (IsEnabled)
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings_Linq.CANT_ADVANCE_WHILE_RUNNING, "AdvanceBy"));
AdvanceTo(val);
}
}
public void Sleep(TRelative time)
{
TAbsolute val = Add(Clock, time);
if (Comparer.Compare(val, Clock) < 0)
throw new ArgumentOutOfRangeException("time");
Clock = val;
}
protected abstract IScheduledItem<TAbsolute> GetNext();
object IServiceProvider.GetService(Type serviceType)
{
return GetService(serviceType);
}
protected virtual object GetService(Type serviceType)
{
if ((object)serviceType == typeof(IStopwatchProvider))
return this;
return null;
}
public IStopwatch StartStopwatch()
{
DateTimeOffset start = ToDateTimeOffset(Clock);
return new VirtualTimeStopwatch(() => ToDateTimeOffset(Clock) - start);
}
}
}