How to Use DefaultIfEmpty in C# LINQ
In C# LINQ, querying empty collections with methods like
First, Single, or Average often
throws an InvalidOperationException. The
DefaultIfEmpty extension method solves this by providing a
fallback element if the source sequence contains no items. This article
explains how DefaultIfEmpty works, how to specify custom
fallback values, and how to use it to implement left outer joins in LINQ
queries.
What is DefaultIfEmpty?
The DefaultIfEmpty method checks whether an
IEnumerable<T> sequence contains any elements. If the
sequence has data, it returns the original sequence untouched. If the
sequence is empty, it returns a new sequence containing a single element
representing a default value.
Basic Usage with Type Defaults
When called without parameters, DefaultIfEmpty()
supplies default(T) for the underlying type—0
for numeric types, false for booleans, and
null for reference types.
using System;
using System.Collections.Generic;
using System.Linq;
List<int> numbers = new List<int>();
// numbers is empty, so DefaultIfEmpty() yields a sequence with one element: 0
int firstNumber = numbers.DefaultIfEmpty().First();
Console.WriteLine(firstNumber); // Output: 0Without DefaultIfEmpty(), calling
numbers.First() on an empty collection would throw an
InvalidOperationException.
Providing a Custom Default Value
You can specify a meaningful fallback value by passing an argument to
the method overload DefaultIfEmpty(TDefault).
List<string> names = new List<string>();
// Returns "Unknown" instead of the default null
string displayName = names.DefaultIfEmpty("Unknown").First();
Console.WriteLine(displayName); // Output: UnknownThis is particularly useful when working with user interfaces, logs,
or reporting where null or 0 does not provide
enough context.
Safe Aggregations
Certain LINQ aggregation methods, such as Average(),
fail when invoked on empty sets. Using DefaultIfEmpty
ensures these calculations execute without throwing exceptions:
List<double> scores = new List<double>();
// Avoids exception by averaging a sequence of [0.0]
double averageScore = scores.DefaultIfEmpty(0.0).Average();
Console.WriteLine(averageScore); // Output: 0Performing Left Outer Joins
In relational database operations, a left outer join returns all rows
from the primary table regardless of whether there is a matching row in
the secondary table. In LINQ, this is achieved by combining
GroupJoin with SelectMany and
DefaultIfEmpty:
var departments = new[]
{
new { Id = 1, Name = "Engineering" },
new { Id = 2, Name = "Marketing" }
};
var employees = new[]
{
new { Name = "Alice", DepartmentId = 1 }
};
var leftJoinQuery = from dept in departments
join emp in employees on dept.Id equals emp.DepartmentId into empGroup
from emp in empGroup.DefaultIfEmpty()
select new
{
Department = dept.Name,
Employee = emp != null ? emp.Name : "No Employee"
};
foreach (var item in leftJoinQuery)
{
Console.WriteLine($"{item.Department}: {item.Employee}");
}
// Output:
// Engineering: Alice
// Marketing: No EmployeeBy calling empGroup.DefaultIfEmpty(), the query ensures
departments without any matching employees still generate a result row
where emp is set to null.