Skip to content

Enumerable.MinBy and Enumerable.MaxBy may or may not throw on empty collections depending on the collection type #62656

@instantsc

Description

@instantsc

Description

#53528 mentions the issues when these methods change their behavior "unpredictably" based on the predicate type. I think the behavior changing based on the source sequence type is no more predictable:

if (!e.MoveNext())
{
  if (default(TSource) is null)
  {
    return default;
  }
  else
  {
    ThrowHelper.ThrowNoElementsException();
  }
}

It is typical for the keys of a collection (Dictionary, HashSet, etc.) to be required to not be null, but never before were null elements discriminated in Enumerable extensions like this. How do I distinguish between

new string[]{}

and

new string[]{null}

using these methods? Did these ifs get in because the *OrDefault versions did not get implemented and this is the compomise? I do not think this is convenient or expected at all. What are users supposed to do in their generic methods that call MinBy, replicate this logic (checking default(TSource)) every single time to work around this behavior?

Reproduction Steps

Call Enumerable.MinBy on a reference type, e.g.:

new string[] {}.MinBy(x=>x)

Expected behavior

a new InvalidOperationException(SR.NoElements) is thrown like for every other method that expects at least a single element, e.g. Single, Min, Max, First.

Actual behavior

null is returned

Regression?

Not a regression

Known Workarounds

Fuff about with ifs (which is not the intended idea of LINQ one would think) or write own extensions methods (which is more difficult now because the problematic framework ones took away the reasonable name). MoreLinq works around this problem by returning an enumerable from Min/MaxBy, which i think is an entirely reasonable approach.

Configuration

.NET SDK 6.0.100

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions