LINQ improvements - FirstOrDefault defaults

Exploring the FirstOfDefault improvements introduced in .NET6

Home DailyDrop

Daily Knowledge Drop

A number of enhancements have been made to LINQ as part of .NET6 - one of those is the ability to set a default value to be returned from .FirstOrDefault().


Examples

List<> is being used in the below examples, but the method is available on all compatible types, not just List<>.

Simple type list

// list of 11 integers
var intValues = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Returns the first value greater than 4. 
// A value from the list will be returned
Console.WriteLine(intValues.FirstOrDefault(i => i > 4));

// Returns the first value greater than 20.
// No qualifying value exists in the list, 
// so the default value of type int will be returned (0 in this case)
Console.WriteLine(intValues.FirstOrDefault(i => i > 20));

// Returns the first value greater than 20. No qualifying value 
// exists in the list, and as the new method override is being used, 
// the explicitly supplied default value will be returned (-1 in this case)
Console.WriteLine(intValues.FirstOrDefault(i => i > 20, -1));

The output:

5
0
-1

Complex type list

The same process can be applied to more complex type. The below example uses a Person record (but the same would apply to a traditional class as well)

var personValues = new List<Person> {
    new Person("Dave",30),
    new Person("Nate",45),
    new Person("Pat",60),
    new Person("Taylor",25),
    new Person("Chris",39)
};

// Returns the first Person with age of 30. A value from the list will be returned
Console.WriteLine(personValues.FirstOrDefault(p => p.Age == 30));

// Returns the first Person whose name starts with "J". 
// No qualifying value exists in the list, so the default value of 
// Person will be returned (null in this case)
Console.WriteLine(personValues.FirstOrDefault(p => p.Name.StartsWith("J")));

// Returns the first _Person_ whose name starts with "J". 
// No qualifying value exists in the list, and as the new method override 
// is being used, the explicitly supplied default value will be returned 
// (Person initialized with "John Doe" and 0 in this case)
Console.WriteLine(personValues.FirstOrDefault(p => p.Name.StartsWith("J"), 
    new Person("John Doe", 0)));

public record Person(string Name, int Age);

The output. The blank line indicates the null record returned from the 2nd call to FirstOrDefault():

Person { Name = Dave, Age = 30 }

Person { Name = John Doe, Age = 0 }

Empty list

This method can also be used to return a specific default value in the case of an empty list.

var stringValues = new List<string>();

// Returns the first value in the list. 
// The list is empty, so the default value of string
// will be returned (empty string in this case)
Console.WriteLine(stringValues.FirstOrDefault());

// Returns the first value in the list. 
// The list is empty, and as the new method override is 
// being used, the explicitly supplied default value
// will be returned ("empty" in this case)
Console.WriteLine(stringValues.FirstOrDefault("empty"));

The output is as follows, the blank line indicating the empty string returned from the 1st call to FirstOrDefault():

     
empty

Conclusion

A small, simple update made to LINQ, but nevertheless a very useful feature which I'm sure will get a fair amount of usage.


Daily Drop 19: 25-02-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net indexer array extend