Six helpful extension methods I use to work with Collections
16 Dec 2022 #tutorial #csharpThis post is part of my Advent of Code 2022.
LINQ is the perfect way to work with collections. It’s declarative and immutable. But, from time to time, I take some extension methods with me to the projects I work with. These are some extension methods to work with collections.
1. Check if a collection is null or empty
These are three methods to check if a collection is null or empty. They’re wrappers around the LINQ Any method.
public static bool IsNullOrEmpty<T>([NotNullWhen(false)] this IEnumerable<T>? collection)
=> collection == null || collection.IsEmpty();
public static bool IsNotNullOrEmpty<T>([NotNullWhen(true)] this IEnumerable<T>? collection)
=> !collection.IsNullOrEmpty();
public static bool IsEmpty<T>(this IEnumerable<T> collection)
=> !collection.Any();
Notice we used the [NotNullWhen]
attribute to let the compiler know if the source collection is null. This way, when we turn on the nullable references feature, the compiler can generate more accurate warnings. If we don’t add this attribute, we get some false positives. Like this one,
IEnumerable<Movie>? movies = null;
if (movies.IsNotNullOrEmpty())
{
movies.First();
// ^^^^^
// CS8604: Possible null reference argument for parameter 'source'
//
// But we don't want this warning here...
}
2. EmptyIfNull
In the same spirit of DefaultIfEmpty, let’s create a method to return an empty collection if the source collection is null. This way, we can “go with the flow” by nesting this new method with other LINQ methods.
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T>? enumerable)
=> enumerable ?? Enumerable.Empty<T>();
For example, we can write,
someNullableCollection.EmptyIfNull().Select(DoSomething);
// ^^^^^
Instead of writing,
someNullableCollection?.Select(DoSomeMapping) ?? Enumerable.Empty<SomeType>();
I found this idea in Pasion for Coding’s Null Handling with Extension Methods.
3. Enumerated
The LINQ Select()
method has an overload to map elements using their position in the source collection. We can use it like this,
movies.Select((movie, position) => DoSomething(movie, position))));
Inspired by Swift Enumerated method, we can write a wrapper around this Select()
overload. Like this,
public static IEnumerable<(int Index, TResult Item)> Enumerated<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
=> source.Select((t, index) => (index, selector(t)));
public static IEnumerable<(int Index, TSource Item)> Enumerated<TSource>(this IEnumerable<TSource> source)
=> source.Enumerated(e => e);
For example, we can write,
foreach (var (index, movie) in movies.Enumerated())
{
Console.WriteLine($"[{index}]: {movie.Name}")l
}
.NET 9 introduced the Index method that works like our Enumerated()
. We don’t need to roll our own method anymore in recent versions of .NET.
Voilà! These are some of my favorite extension methods to work with collections. Some of them are workarounds to avoid the NullReferenceException when working with collections. What extension methods do you use often?
If you want to learn more about LINQ, read my Quick Guide to LINQ.
Happy coding!