C#
Exception Handling
LINQ
Null Return
Error Management

Find and First throws exceptions, how to return null instead?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This topic causes confusion because Find and First do not behave the same way. List<T>.Find already returns the default value when nothing matches, while LINQ First throws InvalidOperationException if the sequence is empty or no element satisfies the predicate. If you want a null-like result instead of an exception, the usual answer is FirstOrDefault, not First.

Find Versus First

Find belongs to List<T>. First belongs to LINQ and works on any IEnumerable<T>.

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5var names = new List<string> { "Ada", "Grace", "Linus" };
6
7string? a = names.Find(x => x == "Alan");
8Console.WriteLine(a is null); // true
9
10string b = names.First(x => x == "Ada");
11Console.WriteLine(b);

If you change the First call to search for a missing value, it throws.

csharp
string missing = names.First(x => x == "Alan");

That throws because First promises an element, not an optional result.

Use FirstOrDefault When No Match Is Acceptable

If returning a default value is acceptable, use FirstOrDefault.

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5var names = new List<string> { "Ada", "Grace", "Linus" };
6
7string? match = names.FirstOrDefault(x => x == "Alan");
8
9if (match is null)
10{
11    Console.WriteLine("No match found");
12}
13else
14{
15    Console.WriteLine(match);
16}

For reference types, the default is null. That makes FirstOrDefault the direct replacement most people want.

Value Types Need Extra Care

For value types, the default is not null. It is the type's zero-like value. For int, that is 0. For bool, that is false. That means FirstOrDefault can be ambiguous if 0 is a valid result.

csharp
1using System;
2using System.Linq;
3
4var numbers = new[] { 10, 20, 30 };
5int result = numbers.FirstOrDefault(x => x == 0);
6Console.WriteLine(result); // 0, but did we find it or not?

If you need a real null for value types, project into a nullable type.

csharp
1int? result = numbers
2    .Where(x => x == 0)
3    .Select(x => (int?)x)
4    .FirstOrDefault();
5
6Console.WriteLine(result is null); // true

That makes the "not found" state explicit.

SingleOrDefault and DefaultIfEmpty

Sometimes FirstOrDefault is not the best semantic choice. If the query should return at most one result and duplicates are a bug, SingleOrDefault expresses that intent better. It still returns a default value when nothing matches, but it throws if more than one match exists.

You can also use DefaultIfEmpty when you want to provide a custom fallback object instead of a default value.

csharp
var fallback = new Person { Name = "Unknown" };
var person = people.Where(p => p.Id == id).DefaultIfEmpty(fallback).First();

That pattern is useful when null would only force more branching later.

Common Pitfalls

The first pitfall is assuming Find throws when no element exists. List<T>.Find does not do that. If code is throwing, the issue is usually First, Single, or another LINQ operator with stricter semantics.

Another common mistake is using FirstOrDefault on a value type and forgetting that the default may be a legitimate business value. In those cases, nullable projection or a custom wrapper is safer.

Developers also sometimes catch InvalidOperationException around First just to simulate optional behavior. That is the wrong abstraction. If missing data is expected, choose FirstOrDefault or SingleOrDefault and let the method communicate intent directly.

Finally, nullable reference types can expose older assumptions. If your project has nullable analysis enabled, pay attention to string? versus string when using FirstOrDefault, because the compiler is correctly telling you the result may be missing.

Summary

  • 'List<T>.Find already returns the default value when nothing matches.'
  • LINQ First throws if the sequence has no matching element.
  • Use FirstOrDefault when a missing result is acceptable.
  • For value types, default values can be ambiguous, so nullable projection may be better.
  • Pick First, FirstOrDefault, or SingleOrDefault based on the semantic rule you actually need.

Course illustration
Course illustration

All Rights Reserved.