Edit

Share via


SYSLIB0061: System.Linq.Queryable.MaxBy and System.Linq.Queryable.MinBy taking an IComparer<TSource> are obsolete.

Starting in .NET 10, the two extension methods System.Linq.Queryable.MaxBy<TSource,TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TSource>) and System.Linq.Queryable.MinBy<TSource,TKey>(IQueryable<TSource>, Expression<Func<TSource,TKey>>, IComparer<TSource>) that accept an IComparer<TSource> are obsolete. Please use the newly added overloads that accept an IComparer<TKey> instead.

Calling these old extension methods in code generates warning SYSLIB0061 at compile time and typically generates a IndexOutOfRangeException at runtime.

Reason for obsoletion

The original MaxBy and MinBy accepting an IComparer<T>? comparer expression parameter were incorrectly implemented using the generic type TSource for the IComparer<T>? comparer type parameter. This is incorrect because the values passed to the Comparer<T>.Compare(T, T) method are selected by the Expression<Func<TSource, TKey>> keySelector expression parameter, thus the extracted value is of generic type TKey.

Note

This would previously work only if TSource and TKey were actually the same constructed type. If the types were distinct then a runtime IndexOutOfRangeException: Index was outside the bounds of the array. would be thrown because the needed extension method for IQueryable<TSource> source could not be found (for example in MaxBy).

Workaround

Use the newly added MaxBy or MinBy method that accepts an IComparer<TKey>? comparer parameter. These will not throw an exception.

For example:

// This worked correctly since TKey and TSource are both int.
Enumerable.Range(1, 10)
    .AsQueryable()
    .MaxBy(key => (0 - key), Comparer<int>.Default);

// This would throw since TKey is string but TSource is int
// and will trigger the obsoletion warning now and would
// throw an exeception at runtime.
Enumerable.Range(1, 10)
    .AsQueryable()
    .MaxBy(key => key.ToString(), Comparer<int>.Default);

// This previously would not compile before to the addition of
// the new methods since TKey is string and TSource is int.
// It will now compile and execute correctly.
Enumerable.Range(1, 10)
    .AsQueryable()
    .MaxBy(key => key.ToString(), Comparer<string>.Default);

Suppress a warning

If you must use the obsolete API, you can suppress the warning in code or in your project file.

To suppress only a single violation, add preprocessor directives to your source file to disable and then re-enable the warning.

// Disable the warning.
#pragma warning disable SYSLIB0061

// Code that uses obsolete API.
// ...

// Re-enable the warning.
#pragma warning restore SYSLIB0061

To suppress all the SYSLIB0061 warnings in your project, add a <NoWarn> property to your project file.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
   ...
   <NoWarn>$(NoWarn);SYSLIB0061</NoWarn>
  </PropertyGroup>
</Project>

For more information, see Suppress warnings.