Collection of clocks hang in a wall

Six helpful extension methods I use to work with Collections

This 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
}

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.

If you want to write more expressive code to work with collections, check my course Getting Started with LINQ on Educative, where I cover from what LINQ is, to refactoring conditionals with LINQ and to the its new methods and overloads in .NET6. All you need to know to start using LINQ in your everyday coding.

Happy coding!