はじめに:「null安全List」は“落とし穴を先に埋めておく道具”
業務コードでありがちな例として、
List<string> names = null;
// ここで落ちる
foreach (var n in names)
{
Console.WriteLine(n);
}
C#「null の可能性がある List に対して、うっかりそのまま LINQ や foreach を回してしまう」
これが、実務でかなり頻出するバグのパターンです。
ここで目指したいのは、
「List が null でも“空のコレクション”として扱えるようにしておく」
という発想です。
“null かもしれない List” を、先に「null 安全な形」に変換してから使うことで、
以降のコードをシンプルに、そして安全にできます。
基本アイデア:null を「空のコレクション」に正規化する
拡張メソッド ToSafeList / OrEmpty を用意する
まずは、「null かもしれない IEnumerable<T> を、絶対に null にならない列に変換する」
という小さなユーティリティを作ります。
using System;
using System.Collections.Generic;
using System.Linq;
public static class EnumerableExtensions
{
public static IEnumerable<T> OrEmpty<T>(this IEnumerable<T>? source)
{
return source ?? Enumerable.Empty<T>();
}
public static List<T> ToSafeList<T>(this IEnumerable<T>? source)
{
return source?.ToList() ?? new List<T>();
}
}
C#ここでの重要ポイントは、
「null だったら Enumerable.Empty<T>() や new List<T>() に置き換える」
という一点だけです。
これで、「null かもしれない」を「空かもしれない」に変換できます。
“空”なら、LINQ も foreach も安全に動きます。
例1:foreach で回すときに null を気にしなくてよくする
Before:毎回 null チェックを書くコード
List<string>? names = GetNamesOrNull();
if (names != null)
{
foreach (var n in names)
{
Console.WriteLine(n);
}
}
C#毎回 if (names != null) を書くのはダルいし、
書き忘れたところで NullReferenceException が飛びます。
After:OrEmpty を通してから回す
List<string>? names = GetNamesOrNull();
foreach (var n in names.OrEmpty())
{
Console.WriteLine(n);
}
C#names が null の場合、OrEmpty() が「空の列」に変換してくれるので、
foreach は単に「何も回らない」だけで終わります。
ここでの重要ポイントは、
「null のときに“例外”ではなく“空”として扱う、というポリシーを決める」
ことです。
このポリシーをユーティリティに閉じ込めておくと、呼び出し側のコードが一気にスッキリします。
例2:LINQ で集計するときに null を気にしない
Before:LINQ の前に null チェックが必要
List<int>? scores = GetScoresOrNull();
int total = 0;
if (scores != null)
{
total = scores.Sum();
}
C#After:OrEmpty を挟んでから LINQ を使う
List<int>? scores = GetScoresOrNull();
int total = scores.OrEmpty().Sum();
C#scores が null なら、OrEmpty() が空の列に変換し、Sum() の結果は 0 になります(LINQ の仕様)。
ここでの重要ポイントは、
「null のときの“意味あるデフォルト”を決めておく」
ことです。
合計なら 0、件数なら 0、最大値・最小値なら別途扱いを決める、など。
少なくとも「NullReferenceException で落ちる」よりは、
“空として扱う”ほうが実務では扱いやすい場面が多いです。
例3:ToSafeList で「絶対 null にならない List」を受け取る
ToSafeList の使いどころ
OrEmpty() は IEnumerable<T> を返しますが、
「この先は List として扱いたい」という場面も多いです。
List<string>? names = GetNamesOrNull();
List<string> safeList = names.ToSafeList();
// ここから先は safeList が null でないことが保証される
Console.WriteLine($"件数: {safeList.Count}");
C#names が null の場合でも、ToSafeList() は空の List<string> を返します。
これで、「この変数は絶対に null ではない」と言い切れるようになります。
ここでの重要ポイントは、
「境界で“null かもしれない”を“null ではない”に変換しておく」
という設計です。
メソッドの入り口や、外部からの入力を受け取った直後に ToSafeList を通しておけば、
内部のロジックでは null を気にせずに List を扱えます。
もう一歩:null 許容参照型(nullable reference types)との組み合わせ
List<T>? と List<T> を意識的に使い分ける
C# 8 以降の「null 許容参照型」を使っている場合、
型システム的にも「null かもしれない List」と「null ではない List」を区別できます。
List<string>? maybeNames = GetNamesOrNull();
List<string> names = maybeNames.ToSafeList(); // ここで“非 null”に正規化
C#このように、
外部から来るもの(DB、API、UI)は List<T>?
内部で使うものは List<T>(ToSafeList 済み)
というルールにしておくと、
コンパイラの警告も味方にしながら、null 安全なコードを書けるようになります。
ここでの重要ポイントは、
「null を“どこまで許すか”を設計として決める」
ことです。
ユーティリティは、その設計を支えるための“変換ポイント”として使います。
実務で意識してほしいこと
「null を返さない」設計に寄せていく
本音を言うと、
「List を返すメソッドは、そもそも null を返さず、空の List を返す」
という設計にできるのが理想です。
// 悪い例(null の可能性がある)
List<User>? GetUsers();
// 良い例(null は返さない)
List<User> GetUsers()
{
return _repository.LoadUsers() ?? new List<User>();
}
C#ただ、既存コードや外部ライブラリでは、
どうしても List<T>? が返ってくることがあります。
そういうときにこそ、OrEmpty や ToSafeList のようなユーティリティが効いてきます。
「null チェックだらけのコード」から卒業する
if (list != null) があちこちに散らばっているコードは、
読みづらいし、どこかでチェック漏れが起きます。
「null かもしれないものは、最初に“空”に正規化してしまう」
というスタイルに切り替えると、
LINQ も foreach も、ずっと気楽に書けるようになります。
まとめ:「null安全Listユーティリティ」は“例外ではなく空として扱うためのクッション”
ポイントを整理すると、こうなります。
OrEmpty() で「null かもしれない列」を「空かもしれない列」に変換する。ToSafeList() で「null かもしれない列」から「絶対 null ではない List」を作る。
foreach や LINQ の前に一度だけこれらを通しておけば、以降のコードで null を気にしなくてよくなる。
外部との境界で null を受け取り、内部では null を排除する、という設計を意識する。
こういう小さなユーティリティを一つずつ持っておくと、
「NullReferenceException に怯えながら書くコード」から、
「安心して LINQ とコレクションを使い倒せるコード」に、じわじわ変わっていきます。

