Day 19 のゴールと全体像
Day 19 では、C# でとても重要なテーマである nullable(ヌラブル) を学びます。 これは「値があるかもしれないし、ないかもしれない」という状態を、安全に・明確に扱うための仕組みです。
学ぶ内容は次の 4 つです。
null- nullable reference types(
string?など) ??(null 合体演算子)?.(null 条件演算子)
これらをステップバイステップでかみ砕きながら、null が原因のエラーを減らす書き方を身につけていきます。
null とは何か
「値が存在しない」という特別な状態
null は、
「値が存在しないことを表す特別な値」
です。
たとえば、
- まだユーザー名が決まっていない
- データベースから値が取得できなかった
- オプション設定が未指定
といったときに、「何もない」という状態を null で表現します。
// ユーザー名がまだ設定されていない状態
string? userName = null;
C#null の危険性:NullReferenceException
null のままの変数に対して、プロパティやメソッドを呼び出そうとすると、 NullReferenceException(ヌル参照例外)というエラーが発生します。
string? name = null;
// name が null なのに Length を読もうとするとエラーになります
int length = name.Length; // 実行時に NullReferenceException
C#この「null に対してアクセスしてしまう」問題を減らすために、 C# には nullable reference types や ??、?. といった仕組みが用意されています。
nullable reference types と ?
「null を許すかどうか」を型で表現する
C# では、参照型(string やクラスなど)に ? を付けることで、
string- 「null を許さない文字列」
string?- 「null を許してもよい文字列」
というように、「null を許すかどうか」を型レベルで表現できます。
// null を許さない(必ず何かしらの文字列が入る前提)
string nonNullName = "Alice";
// null を許す(値がない可能性がある)
string? nullableName = null;
C#「null かもしれない」を意識してコードを書く
string? のように ? を付けると、
「この変数は null になる可能性がある」
ということを、コードを読む人にもコンパイラにも伝えられます。
その結果、
- null チェックを忘れていると警告が出る
- 「ここは null を許している」「ここは許していない」がはっきりする
ので、null が原因のバグを減らしやすくなります。
??(null 合体演算子)
「null だったら代わりの値を使う」
?? は null 合体演算子と呼ばれ、
左側が
nullなら右側の値を使う 左側がnullでなければ左側の値をそのまま使う
という意味を持ちます。
例:ユーザー名が null のときに「Guest」を使う
// ユーザー名(null の可能性あり)
string? userName = null;
// userName が null なら "Guest" を使う
string displayName = userName ?? "Guest";
Console.WriteLine($"表示名:{displayName}");
// 結果:表示名:Guest
C#これは、次の if 文と同じ意味です。
string? userName = null;
string displayName;
if (userName == null)
{
displayName = "Guest";
}
else
{
displayName = userName;
}
C#?? を使うことで、「null だったらこの値を使う」という意図を短く、はっきり書けるようになります。
例:nullable な数値にデフォルト値を与える
int? ageFromDb = null; // データベースから取得した年齢(null の可能性あり)
// null なら 18 を使う
int age = ageFromDb ?? 18;
Console.WriteLine($"年齢:{age}");
// 結果:年齢:18
C#?.(null 条件演算子)
「null じゃないときだけ、プロパティやメソッドにアクセスする」
?. は null 条件演算子と呼ばれ、
左側が null でないときだけ、右側のメンバーにアクセスする 左側が null のときは、全体の結果を null にする
という動きをします。
例:name が null かもしれないときに Length を安全に読む
string? name = null;
// name が null でなければ Length を返し、null なら結果も null になる
int? length = name?.Length;
if (length is not null)
{
Console.WriteLine($"文字数:{length}");
}
else
{
Console.WriteLine("名前が未設定です。");
}
C#ここでのポイントは、
nameがnullのときでも、name?.Lengthは 例外を投げずにnullを返す- その結果を
int?(nullable int)で受け取っている
ということです。
ネストしたオブジェクトに対して使う
class Address
{
public string? City { get; set; }
}
class Person
{
public string? Name { get; set; }
public Address? Address { get; set; }
}
Person? person = null; // person も Address も null の可能性あり
// person が null でなく、Address も null でなく、City も null でないときだけ City を取得
string? city = person?.Address?.City;
Console.WriteLine(city ?? "都市情報なし");
// 結果:都市情報なし
C#?. をチェーンして使うことで、
「どこかで null が出ても安全にスキップして、最終的に null か値かを判断する」
という書き方ができます。
?? と ?. を組み合わせる
「安全にアクセスして、足りなければデフォルト値」
実際のコードでは、?. と ?? を組み合わせて使うことがよくあります。
Person? person = GetPerson(); // 取得できない場合は null かもしれない
// 安全に City にアクセスし、null なら "Unknown" を使う
string displayCity = person?.Address?.City ?? "Unknown";
Console.WriteLine($"都市:{displayCity}");
C#この 1 行には、
personが null かもしれないAddressが null かもしれないCityが null かもしれない- 最終的に null だったら “Unknown” を使う
という意図が、コンパクトに表現されています。
ミニ例題:nullable を使ったプロフィール表示
「ニックネームが未設定なら本名を使う」
次のような仕様を考えてみます。
- ユーザーには「本名」と「ニックネーム」がある
- ニックネームは任意(null の可能性あり)
- 表示名は「ニックネームがあればニックネーム、なければ本名」
これを nullable と ?? で書いてみます。
using System;
class User
{
// 本名は必須なので、null を許さない
public string Name { get; set; }
// ニックネームは任意なので、null を許す
public string? NickName { get; set; }
public User(string name, string? nickName)
{
Name = name;
NickName = nickName;
}
}
class Program
{
static void Main(string[] args)
{
var user1 = new User("山田太郎", "たろー");
var user2 = new User("佐藤花子", null); // ニックネームなし
// ニックネームが null なら本名を使う
string display1 = user1.NickName ?? user1.Name;
string display2 = user2.NickName ?? user2.Name;
Console.WriteLine($"ユーザー1の表示名:{display1}");
Console.WriteLine($"ユーザー2の表示名:{display2}");
Console.ReadLine();
}
}
C#ここでは、
NickNameをstring?にすることで「null を許す」ことを明示NickName ?? Nameで「ニックネームがなければ本名」というロジックを簡潔に表現
できています。
Day 19 のまとめ
Day 19 では、
null:値が存在しないことを表す特別な状態- nullable reference types:
stringとstring?のように、「null を許すかどうか」を型で表現する仕組み ??(null 合体演算子):左側が null のときに右側の値を使う?.(null 条件演算子):左側が null でないときだけメンバーにアクセスし、null なら全体を null にする
という 4 つのテーマを通して、null を安全に扱うための考え方と書き方を学びました。
ぜひ、
- 「この変数は本当に null を許してよいか?」を意識して
?を付けるかどうか決める ??で「null だったらこの値」というデフォルト値を積極的に使う?.で「null かもしれないオブジェクト」に安全にアクセスする?.と??を組み合わせて、ネストしたオブジェクトでも null 安全なコードを書く
といった練習を通して、null に強い、安全で読みやすい C# コードを書けるようになっていってください。
