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

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

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#

ここでのポイントは、

  • 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 = 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#

ここでは、

  • 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をコピーしました