dotnet/reactive · error · ArgumentNullException
Thrown when comparer is null (ArgumentNullException, param…
Error message
Thrown when comparer is null (ArgumentNullException, param name: comparer)
What it means
The comparer-overload MaxByWithTies(source, keySelector, comparer) throws ArgumentNullException with param name 'comparer' when the IComparer<TKey> is null. Unlike Comparer<TKey>.Default used by the two-argument overload, the explicit comparer must be provided.
Solutions
- Pass Comparer<TKey>.Default instead of null when default comparison is desired
- Null-check the comparer before the call and fall back to Comparer<TKey>.Default
- Fix the factory/lookup that produced the null comparer
Example fix
// before items.MaxByWithTies(x => x.Score, null); // after items.MaxByWithTies(x => x.Score, scoreComparer ?? Comparer<int>.Default);
Defensive patterns
Strategy: validation
Validate before calling
if (comparer is null) comparer = Comparer<TKey>.Default; var ties = source.MaxByWithTies(keySelector, comparer);
Type guard
static IComparer<T> OrDefault<T>(IComparer<T>? c) => c ?? Comparer<T>.Default;
Try / catch
try { result = source.MaxByWithTies(sel, cmp); }
catch (ArgumentNullException ex) when (ex.ParamName == "comparer") { result = source.MaxByWithTies(sel); } Prevention
- Use Comparer<T>.Default instead of null to mean 'default comparison'
- Validate comparer factories/registries return non-null
- Coalesce comparer arguments at the pipeline boundary
When it happens
Trigger: Passing a null IComparer<TKey> in the three-argument overload, e.g. items.MaxByWithTies(x => x.Key, null), commonly when the comparer is fetched from a registry or constructed conditionally.
Common situations: Comparer obtained from a dictionary/config that returned null; a custom comparer class whose factory failed; using null intending 'default' semantics.
Related errors
- Value cannot be null. (Parameter 'comparer')
- Value cannot be null. (Parameter 'defaultSource')
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'handler')
- Value cannot be null. (Parameter 'sources')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/21a16565e6be70a8.
Report an issue: GitHub.
Appendix: source
Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/MaxByWithTies.cs:45
}
/// <summary>
/// Returns the elements with the minimum key value by using the specified comparer to compare key values.
/// </summary>
/// <typeparam name="TSource">Source sequence element type.</typeparam>
/// <typeparam name="TKey">Key type.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
/// <param name="comparer">Comparer used to determine the maximum key value.</param>
/// <returns>List with the elements that share the same maximum key value.</returns>
public static IList<TSource> MaxByWithTies<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (keySelector == null)
throw new ArgumentNullException(nameof(keySelector));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
return ExtremaBy(source, keySelector, (key, minValue) => comparer.Compare(key, minValue));
}
private static IList<TSource> ExtremaBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, TKey, int> compare)
{
var result = new List<TSource>();
using (var e = source.GetEnumerator())
{
if (!e.MoveNext())
throw new InvalidOperationException("Source sequence doesn't contain any elements.");
var current = e.Current;
var resKey = keySelector(current);
result.Add(current);
while (e.MoveNext())View on GitHub (pinned to 94b5d5ab91)