はじめに 「null安全文字列」は“落ちないコード”への第一歩
C# で業務コードを書いていると、かなりの頻度で出てくる例外があります。NullReferenceException――いわゆる「ヌルポ」です。
「オブジェクト参照がオブジェクト インスタンスに設定されていません。」
このメッセージを何度見たことか、という人も多いはずです。
その原因のかなりの割合を占めるのが「文字列が null なのに、null じゃない前提で扱っている」パターンです。
ここをきちんとケアしておくと、コードの安定感が一気に上がります。
ここでいう「null安全文字列」とは、
「文字列が null でも落ちないように、最初から“安全な形”にそろえて扱う」
という考え方と、そのための小さなユーティリティ群のことです。
ここでは、プログラミング初心者向けに、
なぜ null が危ないのか
よくある落とし穴
実務で使える null 安全ユーティリティの作り方
C# の言語機能(null 合体演算子など)との組み合わせ方
を、例題付きでかみ砕いて説明していきます。
なぜ文字列の null が危ないのか
「null かもしれない」を忘れた瞬間に落ちる
例えば、こんなコードを見てください。
string name = GetUserName(); // ここで null が返るかもしれない
int length = name.Length; // ここで NullReferenceException の可能性
C#GetUserName が何らかの理由で null を返した場合、name.Length にアクセスした瞬間に NullReferenceException が飛びます。
初心者のうちは、「文字列は空文字か何かが入っているだろう」と無意識に思いがちですが、
実務では「null が普通に飛んでくる」場面がたくさんあります。
データベースの値が NULL だった
外部 API のレスポンスで項目が省略されていた
設定ファイルの値が未設定だった
こういうときに、null をそのまま上流に流してしまうと、
どこかで「null じゃない前提のコード」にぶつかって落ちます。
「null を早めに“無害化”する」という発想
そこで大事になるのが、
「null のままにしておかず、早めに“安全な値”に変えてしまう」
という発想です。
文字列の場合の「安全な値」は、ほとんどの場面で
空文字 ""
です。
つまり、
「null かもしれない文字列」を受け取ったら、
「null なら空文字に変換する」ユーティリティを通してから使う。
これだけで、かなりの NullReferenceException を潰せます。
一番基本のユーティリティ null を空文字に変換する
NullToEmpty の実装
まずは、超基本の 1 本から。
public static class StringSafe
{
public static string NullToEmpty(string? value)
{
return value ?? string.Empty;
}
}
C#これだけです。
でも、これがものすごく効きます。
value ?? string.Empty は「null 合体演算子」と呼ばれる構文で、
左側が null でなければ左側を返す
左側が null なら右側を返す
という意味になります。
つまり、
value が "ABC" なら "ABC" を返すvalue が null なら string.Empty(空文字)を返す
という動きです。
例:null かもしれない値を安全に使う
string? rawName = GetUserNameOrNull();
string safeName = StringSafe.NullToEmpty(rawName);
Console.WriteLine($"名前の長さ: {safeName.Length}");
C#rawName が null でも、safeName は必ず空文字以上なので、safeName.Length で落ちることはありません。
ここでの重要ポイントは、
「null のまま使わない。必ず一度“安全化”してから使う」
という習慣を身につけることです。
トリムもセットでやる null+空白をまとめて整える
「null かもしれないし、空白だけかもしれない」問題
実務では、「null かもしれないし、" "(空白だけ)かもしれない」というケースもよくあります。
例えば、ユーザー入力や CSV の項目などです。
このとき、
null → 空文字" " → 空文字
のように、「実質的に“値なし”」として扱いたいことが多いです。
NullOrWhiteSpace を空文字にそろえる
public static class StringSafe
{
public static string NormalizeNullOrWhiteSpace(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return string.Empty;
}
return value;
}
}
C#string.IsNullOrWhiteSpace は、
null
空文字 ""
空白だけ " "
のどれかなら true を返します。
このユーティリティは、「それらを全部空文字にそろえる」役割を持ちます。
例:入力値を正規化してから保存する
string? rawTitle = ReadFromUserInput();
string title = StringSafe.NormalizeNullOrWhiteSpace(rawTitle);
if (title == string.Empty)
{
Console.WriteLine("タイトル未入力として扱う");
}
else
{
Console.WriteLine($"タイトル: {title}");
}
C#ここでは、「null か空白だけか」をいちいち気にせず、
「空文字なら未入力」というルールに一本化できています。
安全な比較・検索 null を気にせず書けるようにする
文字列比較で null を気にしたくない
例えば、こんなコードを書きたくなる場面があります。
if (input.ToUpper() == "YES")
{
// …
}
C#でも、input が null だと input.ToUpper() の時点で落ちます。
これを避けるには、
input が null でも落ちないようにしてから比較する
というパターンをユーティリティ化しておくと便利です。
EqualsSafe の実装
using System;
public static class StringSafe
{
public static bool EqualsIgnoreCase(string? left, string? right)
{
string l = left ?? string.Empty;
string r = right ?? string.Empty;
return string.Equals(l, r, StringComparison.OrdinalIgnoreCase);
}
}
C#ここでは、
両方とも null なら、両方とも空文字になって true
片方だけ null なら、片方が空文字になって false
という動きになります。
StringComparison.OrdinalIgnoreCase を使うことで、「大文字小文字を区別しない比較」も同時に実現しています。
例:ユーザー入力の YES/NO 判定
string? answer = ReadFromUserInput(); // null の可能性あり
if (StringSafe.EqualsIgnoreCase(answer, "YES"))
{
Console.WriteLine("はいが選ばれました");
}
else
{
Console.WriteLine("はい以外です(いいえ or 未入力)");
}
C#answer が null でも、空文字でも、"yes" でも、"YeS" でも、
落ちずに意図通りに判定できます。
null 安全な連結・フォーマット
連結時の null で落ちはしないが、意図しない文字列になる
実は、C# の文字列連結(+)は、null に対しては例外を投げません。
string? a = null;
string b = "World";
string result = a + b; // "World"
C#このように、左側が null でも "World" になります。
一見安全そうですが、問題は「意図しない結果になっても気づきにくい」ことです。
例えば、「null のときは空文字にしたい」「null のときは特定の文字にしたい」といった要件がある場合、
明示的に「どう扱うか」を決めておいたほうが安心です。
NullToEmpty を通してから連結する
string? firstName = GetFirstNameOrNull();
string? lastName = GetLastNameOrNull();
string fullName =
StringSafe.NullToEmpty(lastName) +
" " +
StringSafe.NullToEmpty(firstName);
Console.WriteLine(fullName);
C#firstName や lastName が null でも、
必ず空文字に変換されてから連結されるので、
「null が紛れ込んだ結果」が出てくることはありません。
「null を許すかどうか」を設計で決める
入口で“null を潰す”か、“null を伝播させる”か
ここまで見てきたように、null 安全文字列の基本は
「null を早めに空文字などに変換してしまう」
ことです。
ただし、設計としてはもう一つの選択肢もあります。
「null は null のまま扱い、“null かもしれない”ことを型で表現する」
C# 8 以降の「nullable 参照型」を使うと、
string は「null を許さない」string? は「null を許す」
という区別ができます。
このとき、
外部から入ってくる値(DB、API、ユーザー入力など)は string?
内部でロジックを組むときは、できるだけ string に変換してから使う
という方針にすると、コードがかなりスッキリします。
その「string? → string への変換」を担うのが、
ここまで見てきたような null 安全ユーティリティです。
「どこで null を潰すか」を決めておくと楽になる
例えば、こんな層構造をイメージしてみてください。
外部入力層(DB、API、UI)
↓
変換・正規化層(ここで null を空文字にするなど)
↓
ドメインロジック層(ここでは基本的に null を扱わない)
この「変換・正規化層」で、NullToEmpty や NormalizeNullOrWhiteSpace を使っておくと、
下の層では「null かもしれない」をいちいち気にしなくて済みます。
「どこで null を潰すか」を決めずに、
あちこちでバラバラに ?? "" を書き始めると、
そのうち「どこが安全でどこが危険か」が分からなくなります。
まとめ 「null安全文字列」は“最初にそろえて、あとは安心して使う”
null 安全文字列の考え方は、とてもシンプルです。
「null かもしれない文字列を、そのまま使わない」
「最初に“安全な形”にそろえてから、あとは普通の文字列として扱う」
そのための小さなユーティリティをいくつか用意しておくだけで、NullReferenceException のかなりの部分を潰せます。
押さえておきたいポイントをまとめると、こうなります。
NullToEmpty で「null を空文字に変換する」習慣をつける。NormalizeNullOrWhiteSpace で「null/空文字/空白だけ」を全部空文字にそろえる。
比較や判定は、EqualsIgnoreCase のような null 安全なラッパーを通して書くとスッキリする。
「どこで null を潰すか」を設計として決めておくと、下の層のコードがシンプルになる。
ここまでできれば、「またヌルポか…」という世界から一歩抜け出して、
「文字列は最初に整えてしまえば、あとは安心して使える」という感覚で C# のコードを書けるようになっていきます。

