diff --git a/Rx.NET/Source/src/System.Reactive/Concurrency/LocalScheduler.TimerQueue.cs b/Rx.NET/Source/src/System.Reactive/Concurrency/LocalScheduler.TimerQueue.cs index 05a74516c2..9b893f1870 100644 --- a/Rx.NET/Source/src/System.Reactive/Concurrency/LocalScheduler.TimerQueue.cs +++ b/Rx.NET/Source/src/System.Reactive/Concurrency/LocalScheduler.TimerQueue.cs @@ -370,7 +370,7 @@ private static void EvaluateLongTermQueue() /// /// Currently not used. /// Currently not used. - internal void SystemClockChanged(object sender, SystemClockChangedEventArgs args) + internal virtual void SystemClockChanged(object sender, SystemClockChangedEventArgs args) { lock (StaticGate) { diff --git a/Rx.NET/Source/src/System.Reactive/Internal/SystemClock.cs b/Rx.NET/Source/src/System.Reactive/Internal/SystemClock.cs index b643eb6825..614fe05c57 100644 --- a/Rx.NET/Source/src/System.Reactive/Internal/SystemClock.cs +++ b/Rx.NET/Source/src/System.Reactive/Internal/SystemClock.cs @@ -21,7 +21,7 @@ public static class SystemClock { private static readonly Lazy ServiceSystemClock = new Lazy(InitializeSystemClock); private static readonly Lazy ServiceSystemClockChanged = new Lazy(InitializeSystemClockChanged); - private static readonly HashSet> SystemClockChanged = new HashSet>(); + internal static readonly HashSet> SystemClockChanged = new HashSet>(); private static IDisposable _systemClockChangedHandlerCollector; private static int _refCount; @@ -55,7 +55,7 @@ public static void Release() } } - private static void OnSystemClockChanged(object sender, SystemClockChangedEventArgs e) + internal static void OnSystemClockChanged(object sender, SystemClockChangedEventArgs e) { lock (SystemClockChanged) { diff --git a/Rx.NET/Source/tests/Tests.System.Reactive/Tests/SystemClockTest.cs b/Rx.NET/Source/tests/Tests.System.Reactive/Tests/SystemClockTest.cs index 84e1c3b650..c69c16eeb2 100644 --- a/Rx.NET/Source/tests/Tests.System.Reactive/Tests/SystemClockTest.cs +++ b/Rx.NET/Source/tests/Tests.System.Reactive/Tests/SystemClockTest.cs @@ -905,6 +905,37 @@ private static void ClockChanged_RefCounting_Callback() Assert.Equal(0, scm.N); } + [Fact] + public void SystemClockChange_SignalNoInvalidOperationExceptionDueToRemove() + { + var local = new RemoveScheduler(); + SystemClock.SystemClockChanged.Add(new WeakReference(local)); + + SystemClock.OnSystemClockChanged(this, new SystemClockChangedEventArgs()); + } + + private class RemoveScheduler : LocalScheduler + { + public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) + { + throw new NotImplementedException(); + } + + internal override void SystemClockChanged(object sender, SystemClockChangedEventArgs args) + { + var target = default(WeakReference); + foreach (var entries in SystemClock.SystemClockChanged) + { + if (entries.TryGetTarget(out var local) && local == this) + { + target = entries; + break; + } + } + SystemClock.SystemClockChanged.Remove(target); + } + } + private class MyScheduler : LocalScheduler { internal List> _queue = new List>();