<PackageReference Include="System.Reactive" Version="4.1.5" />

CatchScheduler<TException>

sealed class CatchScheduler<TException> : SchedulerWrapper where TException : Exception
using System.Reactive.Disposables; using System.Runtime.CompilerServices; namespace System.Reactive.Concurrency { internal sealed class CatchScheduler<TException> : SchedulerWrapper where TException : Exception { private class CatchSchedulerLongRunning : ISchedulerLongRunning { private readonly ISchedulerLongRunning _scheduler; private readonly Func<TException, bool> _handler; public CatchSchedulerLongRunning(ISchedulerLongRunning scheduler, Func<TException, bool> handler) { _scheduler = scheduler; _handler = handler; } public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action) { return this._scheduler.ScheduleLongRunning<(CatchSchedulerLongRunning, Action<TState, ICancelable>, TState)>((this, action, state), (Action<(CatchSchedulerLongRunning, Action<TState, ICancelable>, TState), ICancelable>)delegate((CatchSchedulerLongRunning scheduler, Action<TState, ICancelable> action, TState state) tuple, ICancelable cancel) { try { tuple.action(tuple.state, cancel); } catch (TException val) when () { } }); } } private sealed class CatchSchedulerPeriodic : ISchedulerPeriodic { private sealed class PeriodicallyScheduledWorkItem<TState> : IDisposable { private IDisposable _cancel; private bool _failed; private readonly Func<TState, TState> _action; private readonly CatchSchedulerPeriodic _catchScheduler; public PeriodicallyScheduledWorkItem(CatchSchedulerPeriodic scheduler, TState state, TimeSpan period, Func<TState, TState> action) { _catchScheduler = scheduler; _action = action; Disposable.SetSingle(ref _cancel, scheduler._scheduler.SchedulePeriodic<(PeriodicallyScheduledWorkItem<TState>, TState)>((this, state), period, (Func<(PeriodicallyScheduledWorkItem<TState>, TState), (PeriodicallyScheduledWorkItem<TState>, TState)>)(((PeriodicallyScheduledWorkItem<TState> this, TState state) tuple) => tuple.this?.Tick(tuple.state) ?? default((PeriodicallyScheduledWorkItem<TState>, TState))))); } public void Dispose() { Disposable.TryDispose(ref _cancel); } private (PeriodicallyScheduledWorkItem<TState> this, TState state) Tick(TState state) { if (!_failed) try { return (this, _action(state)); } catch (TException val) { TException arg = (TException)val; _failed = true; if (!_catchScheduler._handler(arg)) throw; Disposable.TryDispose(ref _cancel); return default((PeriodicallyScheduledWorkItem<TState>, TState)); } return default((PeriodicallyScheduledWorkItem<TState>, TState)); } } private readonly ISchedulerPeriodic _scheduler; private readonly Func<TException, bool> _handler; public CatchSchedulerPeriodic(ISchedulerPeriodic scheduler, Func<TException, bool> handler) { _scheduler = scheduler; _handler = handler; } public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action) { return new PeriodicallyScheduledWorkItem<TState>(this, state, period, action); } } private readonly Func<TException, bool> _handler; public CatchScheduler(IScheduler scheduler, Func<TException, bool> handler) : base(scheduler) { _handler = handler; } protected override Func<IScheduler, TState, IDisposable> Wrap<TState>(Func<IScheduler, TState, IDisposable> action) { return delegate(IScheduler self, TState state) { try { return action(GetRecursiveWrapper(self), state); } catch (TException val) when () { return Disposable.Empty; } }; } public CatchScheduler(IScheduler scheduler, Func<TException, bool> handler, ConditionalWeakTable<IScheduler, IScheduler> cache) : base(scheduler, cache) { _handler = handler; } protected override SchedulerWrapper Clone(IScheduler scheduler, ConditionalWeakTable<IScheduler, IScheduler> cache) { return new CatchScheduler<TException>(scheduler, _handler, cache); } protected override bool TryGetService(IServiceProvider provider, Type serviceType, out object service) { service = provider.GetService(serviceType); if (service != null) { if (serviceType == typeof(ISchedulerLongRunning)) service = new CatchSchedulerLongRunning((ISchedulerLongRunning)service, _handler); else if (serviceType == typeof(ISchedulerPeriodic)) { service = new CatchSchedulerPeriodic((ISchedulerPeriodic)service, _handler); } } return true; } } }