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