Back to Blog
C#

C# LINQ Null Handling: Avoiding NullReferenceException in Queries

c# linq null handling: Learn how to handle null values in C# LINQ queries using null-conditional operators, DefaultIfEmpty, and safe projections to avoid runtime excep...

LINQNullReferenceExceptionC# NullableNull-Conditional OperatorDefaultIfEmpty
Illustration of C# LINQ query with null safety mechanisms like null-conditional operator and DefaultIfEmpty.

Handling null values is one of the most common sources of runtime failures in C# LINQ queries. Whether the source collection is null, an element is null, or a property accessed inside a projection is null, the default behavior often throws NullReferenceException. This article covers practical c# linq null handling techniques that keep queries safe without obscuring intent.

Common Null Scenarios in LINQ Queries

LINQ queries fail with null references in a few predictable places. The source sequence itself can be null, as when a method returns IEnumerable<T> but returns null instead of an empty collection. Individual elements can be null, which breaks Where clauses that dereference element properties. Projections that access nested properties also throw when an intermediate object is null. Finally, aggregate operations like FirstOrDefault return null for reference types, and subsequent chained calls on that result can fail. Recognizing these patterns helps you decide which guard is appropriate.

Using Null-Conditional Operators in Projections

The null-conditional operator ?. is the first line of defense inside Select projections. It short-circuits property access when the receiver is null, returning null instead of throwing.

var customers = new List<Customer> { new Customer { Name = "Alice", Address = new Address { City = "Berlin" } }, new Customer { Name = "Bob", Address = null }, null }; var cityNames = customers .Select(c => c?.Address?.City) .ToList();

The ?. operator ensures that c being null or c.Address being null does not raise an exception. The result list contains "Berlin", null, and null. This is useful when you need to preserve the shape of the output and later handle nulls explicitly. Note that ?. does not filter out null entries; it only prevents the exception. If you need to exclude them, combine it with a Where clause.

Handling Null Source Collections with ?. and ??

A null source collection is a different problem. Even Where will throw if the source is null. The null-conditional operator can be applied to the whole sequence, and ?? provides a fallback empty collection.

IEnumerable<Order> orders = GetOrders(); // may return null var total = orders? .Where(o => o.IsActive) .Sum(o => o.Amount) ?? 0;

Here orders?. returns null if orders is null, so the entire chain short-circuits. The ?? 0 supplies a default value for the Sum result. This pattern is compact and avoids scattering null checks throughout the query. It works for any LINQ method that returns a single value. For methods that return a sequence, such as Where or Select, you would use ?? Enumerable.Empty<T>() to produce an empty sequence.

var activeOrders = orders? .Where(o => o.IsActive) .ToList() ?? new List<Order>();

Using DefaultIfEmpty for Empty and Null Sequences

DefaultIfEmpty is designed for cases where you want a fallback value when a sequence is empty. It also works after a null-conditional operator has turned the sequence into null, because the ?? operator can supply an empty sequence first.

var numbers = new List<int?> { 1, null, 3 }; var safeNumbers = numbers? .Where(n => n.HasValue) .Select(n => n.Value) .DefaultIfEmpty(0) .ToList();

If numbers is null, the ?. returns null, and DefaultIfEmpty is never called. To handle that, you need to combine with ?? as shown earlier. DefaultIfEmpty is most useful when you want to guarantee at least one element in the output, which is often required before calling First() or Single().

Null Handling in Joins and Grouping

Joins and grouping introduce additional null risks because the key selector can return null, and the result of a join can contain null elements when using GroupJoin or SelectMany with default empty collections.

var query = from customer in customers join order in orders on customer.Id equals order.CustomerId into customerOrders from order in customerOrders.DefaultIfEmpty() select new { CustomerName = customer?.Name ?? "Unknown", OrderTotal = order?.Amount ?? 0 };

The DefaultIfEmpty() inside the join ensures that customers without orders still appear, with order set to null. The null-conditional operator then safely accesses order.Amount. Without these guards, the query would throw when a customer has no matching orders. Grouping by a key that can be null is also safe because LINQ allows null keys, but any subsequent access to the grouping's elements must still check for null if the elements themselves can be null.

Performance and Allocation Considerations

The null-conditional operator does not add significant runtime cost; it compiles to a simple null check before the member access. In most query pipelines, the dominant cost is the iteration and delegate invocation, not the null guard. However, using ?. inside a Select that is executed against an in-memory collection is straightforward. When the query is translated to SQL by an ORM like Entity Framework Core, the null-conditional operator may be translated to SQL CASE expressions, which can affect query complexity. In that scenario, it is often better to use the database's own null handling, such as COALESCE, through the ORM's mapping, rather than relying on client-side null guards. For in-memory LINQ, the allocation overhead of creating intermediate null values is negligible unless you are processing millions of elements and every projection allocates a new anonymous type. In such cases, consider reusing a single type or using a struct-based approach, but measure before optimizing.

Maintainability and Choosing the Right Approach

The choice between ?., ??, and DefaultIfEmpty depends on the intended behavior. Use ?. when you want to propagate nulls through the pipeline and handle them later. Use ?? when you need a concrete fallback value immediately. Use DefaultIfEmpty when you must guarantee at least one element in the sequence, especially before First() or Single(). Avoid mixing these operators in a way that hides meaningful null values. For example, if a null customer name is a data integrity issue, mapping it to "Unknown" might mask the problem. In that case, let the null propagate and handle it at the boundary. Consistency also matters: if you use ?. in one part of a query, use it throughout the same projection to avoid partial null protection. When writing reusable query helpers, prefer returning an empty collection instead of null from methods, as that removes the need for null-conditional guards on the source. These decisions affect long-term maintainability more than the syntax itself, so choose the approach that makes the null behavior explicit and testable.

c# linq null handling: Practical Usage and Code Examples | RYUSLOG DEV