LINQ in Practice · Lesson 18

DefaultIfEmpty expresses an empty-sequence policy

Choose an explicit fallback without confusing missing observations with real data.

How it works

DefaultIfEmpty returns the original sequence when it contains elements. When the sequence is empty, it supplies one fallback element instead. The sample uses zero as an explicit fallback before Average, allowing an empty set of integer observations to produce a displayed zero rather than throwing for a missing average.

The nonempty sequence is unaffected. Its two and four average to three; the fallback zero is not appended to it. This distinction matters because adding zero to every sequence would change both its count and its average. The operator changes only the empty case, not every calculation.

Whether zero is a truthful replacement is a domain question. No temperature observations and an observed temperature of zero describe different situations. A user interface might need a missing indicator, a nullable result, or a diagnostic message instead of a numeric fallback. The query should reflect that decision rather than selecting a convenient default accidentally.

The type's automatic default can also be misleading. A default reference value may be null, and a default number may look like an ordinary measurement. Supplying an explicit fallback makes the policy easier to see, but it does not prove the fallback is appropriate for the report.

Practice by replacing Average with Max and trying only negative input values. Explain why a zero fallback must not influence a nonempty negative sequence. Then write a helper returning a nullable average, using null to represent no observations, and compare the two API contracts at their call sites.

For grouped data, remember that absent groups are different from empty groups that already exist as objects. DefaultIfEmpty cannot create a missing category by itself. Start from the complete expected category list and perform a left join when the report must include categories with no matching observations, then apply a clear fallback policy to each missing result.

A working example

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

int[] empty = Array.Empty<int>();
int[] values = { 2, 4 };
Console.WriteLine(empty.DefaultIfEmpty(0).Average().ToString("0", CultureInfo.InvariantCulture));
Console.WriteLine(values.DefaultIfEmpty(0).Average().ToString("0", CultureInfo.InvariantCulture));

Expected output

0
3
Try this
A fallback element is introduced only when the entire sequence is empty.