Day 19 のゴールと全体像
Day 19 では、C# でとても重要なテーマである nullable(ヌラブル) を学びます。 これは「値があるかもしれないし、ないかもしれない」という状態を安全に扱うための仕組みです。
学ぶ内容は次の 4 つです。
null- nullable reference types(ヌラブル参照型)
??(null 合体演算子)?.(null 条件演算子)
これらをステップバイステップでかみ砕きながら、 「null が原因のエラーを減らす書き方」を身につけていきます。
null とは何か
「値が存在しない」という特別な状態
null は、
「値が存在しないことを表す特別な値」
です。
例えば、
- まだユーザー名が決まっていない
- データベースから値が取得できなかった
- オプション設定が未指定
といったときに、「何もない」という状態を null で表現します。
string? name = null; // name にはまだ値が入っていない(null)
C#null の危険性:NullReferenceException
null のままの変数に対して、プロパティやメソッドを呼び出そうとすると、 NullReferenceException(ヌル参照例外)というエラーが発生します。
string? name = null;
// これはエラーになります(name が null なのに Length を読もうとしている)
int length = name.Length; // NullReferenceException
C#このようなエラーを防ぐために、C# には nullable reference types や ??、?. といった仕組みが用意されています。
nullable reference types とは
「null になるかもしれない」を型で表現する
C# の参照型(string やクラスなど)は、もともと null を取ることができます。 しかし「この変数は null になってもいいのか?」「絶対に null になってはいけないのか?」が曖昧だと、 バグの原因になります。
そこで導入されたのが nullable reference types です。
string- 「null を許さない文字列」
string?- 「null を許してもよい文字列」
というように、? を付けるかどうかで「null を許すかどうか」を表現します。
// null を許さない(基本的に必ず値が入っている前提)
string nonNullName = "Alice";
// null を許す(値がない可能性がある)
string? nullableName = null;
C#コンパイラが「危ないところ」を警告してくれる
nullable reference types を有効にすると、コンパイラが次のようなことをチェックしてくれます。
string(非 nullable)にnullを代入しようとすると警告string?(nullable)を、null チェックなしで使おうとすると警告
これにより、
「ここは null の可能性があるから、ちゃんとチェックしよう」
という意識をコードに反映しやすくなります。
??(null 合体演算子)
「null だったら代わりの値を使う」
?? は null 合体演算子と呼ばれ、
左側が
nullなら右側の値を使う 左側がnullでなければ左側の値をそのまま使う
という意味を持ちます。
例:ユーザー名が null のときに「Guest」を使う
// ユーザー名を取得する(null の可能性あり)
string? userName = GetUserName();
// userName が null なら "Guest" を使う
string displayName = userName ?? "Guest";
Console.WriteLine($"表示名:{displayName}");
C#このコードは、次の if 文と同じ意味です。
string? userName = GetUserName();
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}");
C#?.(null 条件演算子)
「null じゃないときだけ、プロパティやメソッドにアクセスする」
?. は null 条件演算子と呼ばれ、
左側が null でないときだけ、右側のメンバーにアクセスする 左側が null のときは、全体の結果を null にする
という動きをします。
例:name が null かもしれないときに Length を安全に読む
string? name = GetName(); // 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 = GetPerson(); // person も Address も null の可能性あり
// person が null でなく、Address も null でなく、City も null でないときだけ City を取得
string? city = person?.Address?.City;
// city が null なら "Unknown" を使う
string displayCity = city ?? "Unknown";
Console.WriteLine($"都市:{displayCity}");
C#?. をチェーンして使うことで、
「どこかで null が出ても安全にスキップして、最終的に null か値かを判断する」
という書き方ができます。
?? と ?. を組み合わせる
「安全にアクセスして、足りなければデフォルト値」
実際のコードでは、?. と ?? を組み合わせて使うことがよくあります。
Person? person = GetPerson();
// 安全に 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# コードを書けるようになっていってください。
