{"record":{"id":"19ee31d99c818515","repo":"dotnet/reactive","slug":"action-parameter-action-coredispatcherscheduler","errorCode":null,"errorMessage":"action (Parameter 'action')","messagePattern":"action \\(Parameter 'action'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Concurrency/CoreDispatcherScheduler.cs","lineNumber":239,"sourceCode":"        /// <param name=\"period\">Period for running the work periodically.</param>\n        /// <param name=\"action\">Action to be executed, potentially updating the state.</param>\n        /// <returns>The disposable object used to cancel the scheduled recurring action (best effort).</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"action\"/> is <c>null</c>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\"><paramref name=\"period\"/> is less than <see cref=\"TimeSpan.Zero\"/>.</exception>\n        public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)\n        {\n            //\n            // According to MSDN documentation, the default is TimeSpan.Zero, so that's definitely valid.\n            // Empirical observation - negative values seem to be normalized to TimeSpan.Zero, but let's not go there.\n            //\n            if (period < TimeSpan.Zero)\n            {\n                throw new ArgumentOutOfRangeException(nameof(period));\n            }\n\n            if (action == null)\n            {\n                throw new ArgumentNullException(nameof(action));\n            }\n\n            var timer = CreateDispatcherQueue().CreateTimer();\n\n            var state1 = state;\n\n            timer.Tick += (o, e) =>\n            {\n                state1 = action(state1);\n            };\n\n            timer.Interval = period;\n            timer.Start();\n\n            return Disposable.Create(() =>\n            {\n                var t = Interlocked.Exchange(ref timer, null);\n                if (t != null)","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Concurrency/CoreDispatcherScheduler.cs#L221-L257","documentation":"CoreDispatcherScheduler.SchedulePeriodic<TState>(state, period, action) throws ArgumentNullException because the periodic 'action' delegate is null. The periodic timer invokes this delegate on each tick, so a null delegate is rejected before the WinRT DispatcherQueueTimer is created.","triggerScenarios":"Calling SchedulePeriodic with a null Func<IScheduler,TState,IDisposable>, e.g. an uninitialized member or a lookup returning null for the periodic work function.","commonSituations":"Same as other null-action cases: nullable delegate fields not yet assigned, factory methods returning null, or code paths where the periodic callback is only conditionally created.","solutions":["Supply a non-null action delegate to SchedulePeriodic.","Guard the call site: only call SchedulePeriodic when the periodic callback has been initialized.","Centralize delegate creation so the periodic callback cannot be null."],"exampleFix":"// before\nFunc<IScheduler, int, IDisposable> tick = null;\nscheduler.SchedulePeriodic(0, TimeSpan.FromSeconds(1), tick);\n// after\nFunc<IScheduler, int, IDisposable> tick = (s, st) => { DoWork(); return Disposable.Empty; };\nscheduler.SchedulePeriodic(0, TimeSpan.FromSeconds(1), tick);","handlingStrategy":"validation","validationCode":"// csharp\nif (tickAction == null)\n    throw new ArgumentException(\"Periodic action must be provided\", nameof(tickAction));\nd = scheduler.SchedulePeriodic(state, period, tickAction);","typeGuard":"// csharp\nbool CanSchedulePeriodic<TState>(Func<IScheduler, TState, IDisposable> action) => action is not null;","tryCatchPattern":"// csharp\ntry { d = scheduler.SchedulePeriodic(state, period, action); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"action\") { log.Warn(\"Periodic work not scheduled: null action\"); d = Disposable.Empty; }","preventionTips":["Create periodic callbacks as constants/lambdas at the call site instead of nullable variables","Centralize periodic-work registration in one helper that validates arguments","Enable nullable reference type warnings project-wide"],"tags":["null-argument","scheduler","winrt","csharp"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}