{"record":{"id":"f0cb3c5e689139c0","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-comparer-virtualtimescheduler","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'comparer')","messagePattern":"Value cannot be null\\. \\(Parameter 'comparer'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/VirtualTimeScheduler.cs","lineNumber":40,"sourceCode":"            : this(default!, Comparer<TAbsolute>.Default)\n        {\n            //\n            // NB: We allow a default value for TAbsolute here, which typically is a struct. For compat reasons, we can't\n            //     add a generic constraint (either struct or, better, new()), and maybe a derived class has handled null\n            //     in all abstract methods.\n            //\n        }\n\n        /// <summary>\n        /// Creates a new virtual time scheduler with the specified initial clock value and absolute time comparer.\n        /// </summary>\n        /// <param name=\"initialClock\">Initial value for the clock.</param>\n        /// <param name=\"comparer\">Comparer to determine causality of events based on absolute time.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"comparer\"/> is <c>null</c>.</exception>\n        protected VirtualTimeSchedulerBase(TAbsolute initialClock, IComparer<TAbsolute> comparer)\n        {\n            Clock = initialClock;\n            Comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));\n        }\n\n        /// <summary>\n        /// Adds a relative time value to an absolute time value.\n        /// </summary>\n        /// <param name=\"absolute\">Absolute time value.</param>\n        /// <param name=\"relative\">Relative time value to add.</param>\n        /// <returns>The resulting absolute time sum value.</returns>\n        protected abstract TAbsolute Add(TAbsolute absolute, TRelative relative);\n\n        /// <summary>\n        /// Converts the absolute time value to a DateTimeOffset value.\n        /// </summary>\n        /// <param name=\"absolute\">Absolute time value to convert.</param>\n        /// <returns>The corresponding DateTimeOffset value.</returns>\n        protected abstract DateTimeOffset ToDateTimeOffset(TAbsolute absolute);\n\n        /// <summary>","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/VirtualTimeScheduler.cs#L22-L58","documentation":"The protected VirtualTimeSchedulerBase constructor stores the comparer used to order scheduled work by absolute time. A null comparer would break every Clock comparison and queue ordering, so the constructor throws ArgumentNullException.","triggerScenarios":"Deriving from VirtualTimeSchedulerBase (or VirtualTimeScheduler) and calling the base constructor with base(initialClock, null), typically when the comparer is a field initialized after the base call or a constructor parameter not propagated.","commonSituations":"Writing a custom virtual-time scheduler for tests; copying a scheduler subclass and dropping the Comparer<T>.Default argument; a constructor parameter left null by the caller of the subclass.","solutions":["Pass Comparer<TAbsolute>.Default as the comparer in the base constructor call.","Pass a concrete comparer instance (e.g. Comparer<long>.Create(...)) for custom time types.","Validate the comparer parameter in your subclass constructor before calling base()."],"exampleFix":"// before\npublic MyScheduler(long initialClock, IComparer<long> comparer) : base(initialClock, comparer) { }\nnew MyScheduler(0, null);\n// after\nnew MyScheduler(0, Comparer<long>.Default);","handlingStrategy":"validation","validationCode":"if (comparer == null) comparer = Comparer<TAbsolute>.Default;","typeGuard":"bool ValidComparer<TAbsolute>(IComparer<TAbsolute> c) => c is not null;","tryCatchPattern":"try { new MyScheduler(0, comparer); } catch (ArgumentNullException ex) when (ex.ParamName == \"comparer\") { /* fall back to Comparer<T>.Default */ }","preventionTips":["Always pass Comparer<TAbsolute>.Default unless a custom comparer is required.","In subclass constructors, propagate the comparer parameter and validate it before base()."],"tags":["rx","null-argument","constructor","comparer"],"backgroundTag":"invalid-constructor-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"}