Handling Null Values in LINQ Projections in C

Handling null values during LINQ projections is essential for writing robust C# code that avoids runtime NullReferenceException errors. When transforming collections or database query results into new data shapes using .Select(), source objects or their nested navigation properties may be null. This article covers the primary techniques used to handle null values safely during LINQ projections, including null-conditional operators, null-coalescing fallbacks, conditional expressions, and proper handling of outer joins.

The Null-Conditional Operator (?.)

The null-conditional operator allows you to access members of an object only if that object is not null. If the object is null, the expression evaluates to null instead of throwing an exception.

var userViewModels = users.Select(u => new UserViewModel
{
    Id = u.Id,
    City = u.Address?.City
}).ToList();

If u.Address is null, u.Address?.City safely resolves to null. Note that if the projected property is a non-nullable value type (like an int), the null-conditional operator turns the result into a nullable type (int?).

The Null-Coalescing Operator (??)

To provide a default value when a property or nested property is null, combine the null-conditional operator with the null-coalescing operator (??):

var userViewModels = users.Select(u => new UserViewModel
{
    Id = u.Id,
    City = u.Address?.City ?? "Unknown",
    PostalCode = u.Address?.PostalCode ?? 0
}).ToList();

If u.Address or City is null, "Unknown" is assigned. This approach prevents downstream code from having to check for null strings or missing values.

Ternary Conditional Expressions

When projection logic requires complex condition checking or alternative object instantiation, a ternary expression (condition ? then : else) provides explicit control:

var userViewModels = users.Select(u => new UserViewModel
{
    Id = u.Id,
    AddressSummary = u.Address != null 
        ? $"{u.Address.Street}, {u.Address.City}" 
        : "No Address Provided"
}).ToList();

This ensures the string interpolation only executes when the underlying object exists.

Handling Nulls in GroupJoins and Left Outer Joins

When performing left outer joins using LINQ's GroupJoin and DefaultIfEmpty, elements from the right side of the join will be null if no match exists. You must account for these nulls inside the final projection:

var query = from user in users
            join order in orders on user.Id equals order.UserId into userOrders
            from order in userOrders.DefaultIfEmpty()
            select new UserOrderDto
            {
                UserId = user.Id,
                UserName = user.Name,
                OrderId = order != null ? order.Id : (int?)null,
                OrderTotal = order?.Total ?? 0m
            };

Using DefaultIfEmpty() provides a sequence with a single null element when no matching records exist, making the order != null check mandatory.

LINQ to Entities vs. LINQ to Objects

Be aware of where your LINQ query executes:

  • LINQ to Objects (In-Memory): Evaluates strictly in C#. Accessing a property on a null object immediately throws a NullReferenceException unless guarded by ?. or conditional checks.
  • LINQ to Entities (EF Core / Database): Translates expressions into SQL. SQL handles nulls via LEFT JOIN semantics and returns NULL without throwing errors. However, once the query projects into in-memory types or uses client-side evaluation, null handling must still conform to standard C# rules to prevent mapping issues.