CodeGym /コース /C# SELF /値型のためのNullable型

値型のためのNullable型

C# SELF
レベル 14 , レッスン 0
使用可能

1. はじめに

こんな状況を想像してみて。コードで猫のデータを管理してるとする。猫の年齢だけじゃなくて、「データなし」とか「年齢不明」みたいな状態も保存したいんだよね。0を使うこともできるけど、ゼロって普通に有効な年齢だよね。

int age = 0; // 猫の年齢。でも0って何?子猫?それとも「不明」?

問題は、intは整数しか入らなくて、「データなし」っていう特別な値がないこと。もし年齢が文字列ならnullを入れられるけど、数字だとそうはいかないんだ:

int age = null; // エラー! int型の変数にnullは入れられない

これは、値型struct、たとえばintdoubleDateTimebool)は必ず何か値を持ってるからなんだ。参照型と違って「空っぽ」な状態がない(参照型ならnullは「オブジェクトがない」って意味になる)。

実際によくある話:
この制限を回避するために、プログラマーは「特別な値」を考えたりする。たとえば-1int.MaxValueを「値なし」として使う。でもこれってダサいし、間違えやすいし、危険。実際の値とダミー値を間違えやすいからね。

2. Nullable型:「null」を持てる型

アイデア

じゃあ、普通の数字(というか全部の値型)にも値だけじゃなくてnullを入れられるようにしたらどう?
C#ではNullable<T>っていう特別なラッパークラスでこれができる。このクラスはT型の値か、何もない(つまりnull)か、どっちかを持てるんだ。

書き方

int? age = null; // ageは数字でもnullでもOK
?を使ったnullable型の宣言

C#のコンパイラは、こういうコードを見ると実際にはこう解釈してる:

Nullable<int> age = new Nullable<int>(); // ageは値を持ってない

値を明示的に指定したい場合はこう:

Nullable<int> age = new Nullable<int>(42); // ageは42を持ってる

つまり、クエスチョンマークを付けるとどんな値型でもnullableバージョンにできるってこと:

  • int?(これはNullable<int>と同じ)
  • double?
  • DateTime?
  • 他のstructも全部OK

よく使うstructのNullableラッパー

普通の型 Nullable型 書き方の例
int
int?
int? a = null;
double
double?
double? x = 3.14;
bool
bool?
bool? ok = null;
DateTime
DateTime?
DateTime? d = null;

ラッパークラスを使って長く書くこともできるよ:


Nullable<int> pages = null;
        
長い書き方

でもint?って書いた方が短いし、カッコいいよね。

3. Nullable型の使い方

代入とチェック

nullの代入は参照型と同じ感じでできるよ:

宣言と代入

int? temperature = null;
temperature = 25;

nullチェック

nullable型に本当に値が入ってるかどうか知りたいときは?

if (temperature != null)
{
    Console.WriteLine($"温度: {temperature}");
}
else
{
    Console.WriteLine("温度データなし");
}

Nullable型のプロパティ:.HasValue.Value

nullable型には大事なプロパティが2つあるよ:

  • .HasValue — 何か値が入ってたらtrueを返す(nullじゃなければ)。
  • .Value — 値そのもの(なければ例外になる)。
int? temperature = null;
if (temperature.HasValue) //例外は起きない!
{
    Console.WriteLine($"温度: {temperature.Value}°C");
}
else
{
    Console.WriteLine("温度は不明");
}

このコードはちゃんと動くよ:temperatureはnullじゃなくて、中身がnullなんだ。Nullable型ならいつでもHasValueを呼べる。でも.Valueを値なしで呼ぶとInvalidOperationExceptionが出るから、先に値があるかチェックしよう!

省略した書き方

多くの場合、nullable型の変数をそのまま使えばC#が勝手に判断してくれるよ:

int? hours = null;
Console.WriteLine(hours); // 何も出力されない(空っぽ)
hours = 10;
Console.WriteLine(hours); // 10が出力される

4. 演算とnullable型:計算、比較、変換

演算:どうなる?

どっちかのオペランドがnullableなら、結果もnullableになるよ。
どっちかがnullなら、結果もnullになる。

int? a = 5;
int? b = null;
int? sum = a + b; // sum == null

int? c = 10;
int? d = 15;
int? total = c + d; // total == 25

比較演算

nullable型と普通の数字も比較できるよ:

int? score = null;
if (score > 0) Console.WriteLine("いいスコアだね!");
else Console.WriteLine("スコアなし"); // こっちが実行される

scoreがnullなら、score > 0falseになるよ。

明示的・暗黙的な変換

  • 普通の型→nullable:自動でOK。
  • nullable→普通の型:nullじゃなければOK(nullだと例外)。
int? x = 3;
int y = x.Value; // xがnullじゃなければOK

// 暗黙的に
int? z = y;

5. Nullableとメソッド:パラメータと戻り値

nullableな値を返す

メソッドが必ずしも結果を返せない場合、戻り値をnullable型にしよう:

// ログインでユーザーを探して、年齢を返す。見つからなければnull
int? FindUserAge(string login)
{
    // ... ここに検索ロジック
    return null; // 見つからなかった場合
}

nullableパラメータ

パラメータにnullable値を受け取ることで、「あるかも、ないかも」を明示できるよ。

void PrintTemperature(int? temp)
{
    if (temp == null)
        Console.WriteLine("温度は不明");
    else
        Console.WriteLine($"温度: {temp}度");
}
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION