dotnet/reactive · error · ArgumentNullException

comparer

Error message

comparer

What it means

ArgumentNullException thrown synchronously by the DistinctUntilChanged(source, comparer) overload when the IEqualityComparer<TSource> argument is null. The comparer is required because the operator must compare consecutive elements; there is no default-fallback in this overload (use the single-argument overload for default comparison).

Solutions

  1. Pass a real comparer, e.g. EqualityComparer<TSource>.Default
  2. Use the comparer-less overload DistinctUntilChanged(source) when default equality is intended
  3. Fix the comparer factory/lookup returning null

Example fix

// before
var result = source.DistinctUntilChanged(comparer); // comparer may be null
// after
var result = source.DistinctUntilChanged(comparer ?? EqualityComparer<MyType>.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (comparer is null) comparer = EqualityComparer<TSource>.Default;

Type guard

static bool HasComparer<T>(IEqualityComparer<T>? c) => c is not null;

Try / catch

try { var r = source.DistinctUntilChanged(cmp); }
catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { /* fall back to default comparer */ }

Prevention

When it happens

Trigger: Calling DistinctUntilChanged(source, null) explicitly, or passing a comparer variable/field that was never assigned, or a factory method that returned null for the comparer.

Common situations: Conditional comparer selection where the else-branch leaves the variable null; DI-resolved comparers not registered; config-driven comparer lookup miss.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/fb6abff26141b130. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/DistinctUntilChanged.cs:25

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> DistinctUntilChanged<TSource>(IAsyncObservable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Create(source, static (source, observer) => source.SubscribeSafeAsync(AsyncObserver.DistinctUntilChanged(observer)));
        }

        public static IAsyncObservable<TSource> DistinctUntilChanged<TSource>(IAsyncObservable<TSource> source, IEqualityComparer<TSource> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return Create(
                source,
                comparer,
                static (source, comparer, observer) => source.SubscribeSafeAsync(AsyncObserver.DistinctUntilChanged(observer, comparer)));
        }

        public static IAsyncObservable<TSource> DistinctUntilChanged<TSource, TKey>(IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));

            return Create(
                source,
                keySelector,
                static (source, keySelector, observer) => source.SubscribeSafeAsync(AsyncObserver.DistinctUntilChanged(observer, keySelector)));

View on GitHub (pinned to 94b5d5ab91)