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);
        }
    }
}