dotnet/reactive · error · ArgumentNullException

comparer

Error message

comparer

What it means

System.Reactive throws ArgumentNullException immediately when the IEqualityComparer<TSource> passed to Contains is null. The comparer is mandatory on this overload because equality of TSource is undefined without it; the null check runs synchronously at the call site before delegating to the implementation. Passing null here instead of using the comparer-less overload is a common mistake.

Solutions

  1. Call the comparer-less overload source.Contains(value) when default EqualityComparer<T>.Default is desired
  2. Pass EqualityComparer<TSource>.Default explicitly instead of null
  3. Guard the comparer before calling: comparer != null ? source.Contains(v, comparer) : source.Contains(v)
  4. Fix the resolver that produced the null comparer and register/choose a valid one

Example fix

// before
var has = names.Contains("alice", (IEqualityComparer<string>)null);
// after
var has = names.Contains("alice", StringComparer.OrdinalIgnoreCase);
// or for default equality:
var has = names.Contains("alice");
Defensive patterns

Strategy: validation

Validate before calling

var has = comparer != null
    ? source.Contains(value, comparer)
    : source.Contains(value);

Type guard

bool HasComparer<T>(IEqualityComparer<T> comparer) => comparer != null || EqualityComparer<T>.Default != null;

Try / catch

try
{
    var has = source.Contains(value, comparer);
}
catch (ArgumentNullException ex) when (ex.ParamName == "comparer")
{
    // fall back to default equality
    var has2 = source.Contains(value);
}

Prevention

When it happens

Trigger: Calling source.Contains(value, null) when intending the default-equality overload, or passing a comparer variable resolved from configuration/DI that was not registered.

Common situations: Generic helper code that always forwards a comparer parameter which is null in some paths; config-driven comparer selection failing to match a known name; refactors that added the comparer overload without branching on null.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Aggregates.cs:663

        /// Determines whether an observable sequence contains a specified element by using a specified System.Collections.Generic.IEqualityComparer{T}.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <param name="source">An observable sequence in which to locate a value.</param>
        /// <param name="value">The value to locate in the source sequence.</param>
        /// <param name="comparer">An equality comparer to compare elements.</param>
        /// <returns>An observable sequence containing a single element determining whether the source sequence contains an element that has the specified value.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="comparer"/> is null.</exception>
        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>
        public static IObservable<bool> Contains<TSource>(this IObservable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (comparer == null)
            {
                throw new ArgumentNullException(nameof(comparer));
            }

            return s_impl.Contains(source, value, comparer);
        }

        #endregion

        #region + Count +

        /// <summary>
        /// Returns an observable sequence containing an <see cref="int" /> that represents the total number of elements in an observable sequence.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <param name="source">An observable sequence that contains elements to be counted.</param>
        /// <returns>An observable sequence containing a single element with the number of elements in the input sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
        /// <exception cref="OverflowException">(Asynchronous) The number of elements in the source sequence is larger than <see cref="long.MaxValue"/>.</exception>
        /// <remarks>The return type of this operator differs from the corresponding operator on IEnumerable in order to retain asynchronous behavior.</remarks>

View on GitHub (pinned to 94b5d5ab91)