{"record":{"id":"00b7a0f5c4c13399","repo":"dotnet/reactive","slug":"argumentnullexception-nameof-comparer","errorCode":null,"errorMessage":"ArgumentNullException(nameof(comparer))","messagePattern":"ArgumentNullException\\(nameof\\(comparer\\)\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Linq/Operators/DistinctUntilChanged.cs","lineNumber":137,"sourceCode":"\n        public static IAsyncObserver<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObserver<TSource> observer, Func<TSource, ValueTask<TKey>> keySelector)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n\n            return DistinctUntilChanged(observer, keySelector, EqualityComparer<TKey>.Default);\n        }\n\n        public static IAsyncObserver<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObserver<TSource> observer, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)\n        {\n            if (observer == null)\n                throw new ArgumentNullException(nameof(observer));\n            if (keySelector == null)\n                throw new ArgumentNullException(nameof(keySelector));\n            if (comparer == null)\n                throw new ArgumentNullException(nameof(comparer));\n\n            var hasCurrentKey = false;\n            var currentKey = default(TKey);\n\n            return Create<TSource>(\n                async x =>\n                {\n                    var key = default(TKey);\n\n                    try\n                    {\n                        key = keySelector(x);\n                    }\n                    catch (Exception ex)\n                    {\n                        await observer.OnErrorAsync(ex).ConfigureAwait(false);\n                        return;\n                    }","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Linq/Operators/DistinctUntilChanged.cs#L119-L155","documentation":"The sync-keySelector DistinctUntilChanged<TSource,TKey> overload throws ArgumentNullException when the IEqualityComparer<TKey> comparer is null. The operator calls comparer.Equals on every notification, so a null comparer would crash mid-stream; it is rejected eagerly instead.","triggerScenarios":"Calling DistinctUntilChanged(observer, keySelector, null) with an explicit comparer argument that is null.","commonSituations":"A comparer resolved from a registry/DI container that returned null; a nullable comparer field; callers intending 'default comparer' passing null instead of EqualityComparer<TKey>.Default.","solutions":["Pass EqualityComparer<TKey>.Default when you want default semantics instead of null.","Pass a concrete comparer instance (e.g. StringComparer.Ordinal).","If the comparer is resolved at runtime, fall back to EqualityComparer<TKey>.Default when resolution returns null."],"exampleFix":"// before\nvar op = AsyncObserver.DistinctUntilChanged(observer, x => x.Name, cfg.Comparer); // null\n// after\nvar cmp = cfg.Comparer ?? EqualityComparer<string>.Default;\nvar op = AsyncObserver.DistinctUntilChanged(observer, x => x.Name, cmp);","handlingStrategy":"validation","validationCode":"var cmp2 = comparer ?? EqualityComparer<TKey>.Default;\nvar res = AsyncObserver.DistinctUntilChanged(observer, keySelector, cmp2);","typeGuard":"static IEqualityComparer<TKey> OrDefault<TKey>(IEqualityComparer<TKey>? c) => c ?? EqualityComparer<TKey>.Default;","tryCatchPattern":"try { var res = AsyncObserver.DistinctUntilChanged(observer, keySelector, comparer); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"comparer\") { comparer = EqualityComparer<TKey>.Default; }","preventionTips":["Use EqualityComparer<T>.Default instead of null for default equality.","Wrap custom comparer resolution in a helper that never returns null.","Add unit tests that exercise comparer resolution from config/DI."],"tags":["argument-null","comparer","async-rx","distinct-until-changed"],"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"}