【C#】null許容値型 (Nullable Value Types) の基本:int? の宣言から ?? 演算子、パターンマッチングまで

目次

値型における null の扱い

C#において、intdoubleboolDateTimeといった「値型(Value Type)」は、原則として必ず何らかの値を持ち、nullを代入することができません。

しかし、データベースのテーブルで数値カラムがNULLを許可している場合や、APIのレスポンスで数値項目が欠落している場合など、「値が存在しない(null)」という状態を値型でも表現したい場面は多々あります。

このような場合に利用されるのが、「null許容値型(Nullable Value Types)」です。この記事では、null許容値型の定義方法、安全な値の取り出し方、そしてnull合体演算子などの便利な機能について解説します。


null許容値型の定義

値型の型名の後ろに ? を付けることで、その型をnull許容型として定義できます。これにより、通常の数値に加えて null を代入可能になります。

コード例:宣言と代入

using System;

public class NullableDeclarationExample
{
    public static void Main()
    {
        // int型に null は代入できないが、int? 型なら可能
        int? score = null;
        
        // double? 型
        double? temperature = 25.5;

        // DateTime? 型
        DateTime? lastLoginTime = null;

        Console.WriteLine($"score: {score}"); // 何も表示されない (null)
        Console.WriteLine($"temperature: {temperature}");
    }
}

Nullable<T>T?

int? という記述は、実際には System.Nullable<int> 構造体の省略記法(シンタックスシュガー)です。以下の2行は完全に同じ意味を持ちます。

int? num1 = 10;
Nullable<int> num2 = 10;

一般的には、簡潔な int?DateTime? という記述が推奨されます。


値のチェックと取得 (HasValue, .Value)

null許容値型の変数が、現在「値を持っているか」あるいは「nullか」を確認するには、HasValueプロパティを使用します。また、実際の値を取得するにはValueプロパティを使用します。

注意点: Valueプロパティは、変数がnullの状態でアクセスすると InvalidOperationException 例外が発生します。そのため、必ず事前にHasValuenullチェックを行う必要があります。

コード例:安全な値の取得

using System;

public class NullableCheckExample
{
    public static void Main()
    {
        int? databaseId = 105;

        // 値を持っているかチェック (null でないか)
        if (databaseId.HasValue)
        {
            // Value プロパティで、中身の int 型の値を取り出す
            int id = databaseId.Value;
            Console.WriteLine($"IDは {id} です。");
        }
        else
        {
            Console.WriteLine("IDは設定されていません。");
        }

        // 以下の書き方でも同じ判定が可能
        // if (databaseId != null) { ... }
    }
}

null合体演算子 (??) によるデフォルト値

「変数が null の場合はデフォルト値(例えば 0 や -1)を使い、値がある場合はその値を使う」という処理は頻繁に行われます。

これを簡潔に記述できるのが null合体演算子 (??) です。

コード例:?? 演算子

using System;

public class NullCoalescingExample
{
    public static void Main()
    {
        int? inputPrice = null;

        // inputPrice が null なら 0 を代入する
        int finalPrice = inputPrice ?? 0;

        Console.WriteLine($"確定価格: {finalPrice}");

        // 別の例: 値が入っている場合
        int? stock = 50;
        int currentStock = stock ?? 0; // 50 が代入される
        
        Console.WriteLine($"在庫数: {currentStock}");
    }
}

パターンマッチング (is) による安全な取り出し

C# 7.0以降では、is 演算子を使用したパターンマッチングにより、nullチェックと値の取り出し(アンボクシング)を同時に、より安全に行うことができます。

この方法を使用すれば、HasValueを確認してから.Valueにアクセスする手間が省けます。

コード例:is 演算子

using System;

public class PatternMatchingExample
{
    public static void Main()
    {
        double? sensorValue = 12.5;

        // sensorValue が null でなければ、その値を val に代入して true ブロックを実行
        if (sensorValue is double val)
        {
            // ここでは val は通常の double 型として扱える
            Console.WriteLine($"センサー値: {val:F1}");
        }
        else
        {
            Console.WriteLine("センサー値は取得できませんでした。");
        }

        // null の場合
        double? emptyValue = null;
        if (emptyValue is double v)
        {
            Console.WriteLine(v);
        }
        else
        {
            Console.WriteLine("値は null です。");
        }
    }
}

まとめ

null許容値型(Nullable<T>)は、値型に「値がない状態」を持たせるための重要な機能です。

  • 宣言: int? のように型名に ? を付けます。
  • 判定: HasValue プロパティか、!= null で確認します。
  • デフォルト値: ?? 演算子を使うと、null時の代替値を1行で記述できます。
  • 取得: 最近のC#では、if (variable is int value) のようなパターンマッチングを使用するのが、安全かつ簡潔で推奨されます。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次