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;
using System.Runtime.CompilerServices;
namespace System.Reactive.Concurrency
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public abstract class VirtualTimeSchedulerBase<[System.Runtime.CompilerServices.Nullable(0)] TAbsolute, [System.Runtime.CompilerServices.Nullable(2)] TRelative> : IScheduler, IServiceProvider, IStopwatchProvider where TAbsolute : IComparable<TAbsolute>
{
[System.Runtime.CompilerServices.NullableContext(0)]
private sealed class VirtualTimeStopwatch : IStopwatch
{
[System.Runtime.CompilerServices.Nullable(1)]
private readonly VirtualTimeSchedulerBase<TAbsolute, TRelative> _parent;
private readonly DateTimeOffset _start;
public TimeSpan Elapsed => _parent.ClockToDateTimeOffset() - _start;
[System.Runtime.CompilerServices.NullableContext(1)]
public VirtualTimeStopwatch(VirtualTimeSchedulerBase<TAbsolute, TRelative> parent, DateTimeOffset start)
{
_parent = parent;
_start = start;
}
}
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<[System.Runtime.CompilerServices.Nullable(2)] TState>(TState state, TAbsolute dueTime, Func<IScheduler, TState, IDisposable> action);
public IDisposable ScheduleRelative<[System.Runtime.CompilerServices.Nullable(2)] 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<[System.Runtime.CompilerServices.Nullable(2)] TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException("action");
return ScheduleAbsolute(state, this.Clock, action);
}
public IDisposable Schedule<[System.Runtime.CompilerServices.Nullable(2)] 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<[System.Runtime.CompilerServices.Nullable(2)] 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;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
2,
1
})]
protected abstract IScheduledItem<TAbsolute> GetNext();
[return: System.Runtime.CompilerServices.Nullable(2)]
object IServiceProvider.GetService(Type serviceType)
{
return GetService(serviceType);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
protected virtual object GetService(Type serviceType)
{
if (serviceType == typeof(IStopwatchProvider))
return this;
return null;
}
public IStopwatch StartStopwatch()
{
DateTimeOffset start = ClockToDateTimeOffset();
return new VirtualTimeStopwatch(this, start);
}
private DateTimeOffset ClockToDateTimeOffset()
{
return ToDateTimeOffset(Clock);
}
}
}