基礎から学ぶC#入門 90日コース | 制御構文・メソッド - Day 19:nullable

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

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#

ここでのポイントは、

  • namenull のときでも、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#

ここでは、

  • NickNamestring? にすることで「null を許す」ことを明示
  • NickName ?? Name で「ニックネームがなければ本名」というロジックを簡潔に表現

できています。

Day 19 のまとめ

Day 19 では、

  • null:値が存在しないことを表す特別な状態
  • nullable reference typesstringstring? のように、「null を許すかどうか」を型で表現する仕組み
  • ??(null 合体演算子):左側が null のときに右側の値を使う
  • ?.(null 条件演算子):左側が null でないときだけメンバーにアクセスし、null なら全体を null にする

という 4 つのテーマを通して、null を安全に扱うための考え方と書き方を学びました。

ぜひ、

  • 「この変数は本当に null を許してよいか?」を意識して ? を付けるかどうか決める
  • ?? で「null だったらこの値」というデフォルト値を積極的に使う
  • ?. で「null かもしれないオブジェクト」に安全にアクセスする
  • ?.?? を組み合わせて、ネストしたオブジェクトでも null 安全なコードを書く

といった練習を通して、null に強い、安全で読みやすい C# コードを書けるようになっていってください。

タイトルとURLをコピーしました