• システム開発に関わる内容をざっくりと書いていく

System.NullReferenceException C# 発生原因と対策

System.NullReferenceException は、C# で一番よく見る例外のひとつ。「オブジェクト参照がオブジェクト インスタンスに設定されていません」と出て、処理が止まる。

この記事では、よくある発生原因現場で使える対策をざっくり逆引きできるようにまとめる。


先に結論

NullReferenceException の本体はシンプルで、null のままの参照に対してメンバーアクセスしたときに起きる。

string name = null;
int len = name.Length; // NullReferenceException

対策の型もだいたい決まっている。

  • どこが null かを特定する(スタックトレース)
  • null になり得る前提で書く(null 条件演算子、早期 return)
  • そもそも null を作らない(初期化、DI、バリデーション)
  • nullable 参照型でコンパイル時に潰す

よくある発生原因(逆引き)

1. 変数を初期化していない / 代入忘れ

User user = null;
// どこかで取得失敗して null のまま
Console.WriteLine(user.Name);

API レスポンス、DB 検索、辞書の取得失敗あとで起きやすい。

2. ネストしたプロパティの途中が null

// order はあるが Customer が null
var city = order.Customer.Address.City;

「最後のプロパティが怪しい」と思いがちだが、途中の参照が null なことが多い。

3. コレクションの要素が null

var users = new List<User?> { new User("A"), null };
foreach (var u in users)
{
Console.WriteLine(u.Name); // 2件目で例外
}

4. イベント / デリゲートが未登録

public event Action? OnSaved;
public void Save()
{
OnSaved(); // 購読者がいないと NullReferenceException
}

5. DI や設定値の取りこぼし

コンストラクタ注入漏れ、オプションクラス未バインド、GetService で null を受け取ってそのまま使う、など。アプリ起動直後ではなく、特定画面・特定リクエストだけ落ちることもある。


現場での切り分け手順

  1. スタックトレースで例外行を特定する
  2. その行の「ドットの左側」を全部疑う(a.b.c なら aa.b
  3. 直前の取得処理(API / DB / キャッシュ)が失敗していないか確認
  4. 再現データ(null になり得る入力)を用意して再実行

ログに「どの ID のとき落ちたか」が残っていると一気に楽になる。


対策パターン

1. null 条件演算子と早期 return

var city = order?.Customer?.Address?.City;
if (string.IsNullOrEmpty(city))
{
return;
}

2. 明示的にガードする

ArgumentNullException.ThrowIfNull(user);
ArgumentNullException.ThrowIfNull(user.Name);

入り口で落とした方が、後段の NullReferenceException より原因がわかりやすい。

3. イベントは null 条件で発火

OnSaved?.Invoke();

4. nullable 参照型を有効にする

#nullable enable
User? user = FindUser(id);
if (user is null) return;
Console.WriteLine(user.Name); // ここでは user は非 null

コンパイル時点で「null の可能性がある」と怒ってくれるので、実行時例外を減らせる。


やりがちな落とし穴

  • catch (NullReferenceException) で握りつぶす(原因が見えなくなる)
  • 全部 ? 付けて黙らせる(本来必須の値が黙って欠ける)
  • !(null 免除演算子)を根拠なく多用する
  • 「前は動いていた」ケースで、データ欠落や設定漏れを疑わない

ざっくりまとめ

  • NullReferenceException は「null に対するメンバーアクセス」
  • まずスタックトレースで、ドットの左側を洗う
  • 応急は ? と早期 return、本丸は初期化・バリデーション・nullable 参照型
  • 例外を隠すより、null を作らない設計の方が強い

似た系統だと、ArgumentNullException や nullable 関連の警告もセットで押さえておくと実務で困りにくい。