目次

キーワード

概要

通常、「値型」は null 値(無効な値)を取れません。 ところが、データベース等、一部のアプリケーションでは、 値型の通常の(有効な)値と null(無効な値)を取るような型が欲しいときがあります。 そこで、C# 2.0 では、null 許容型(Nullable 型)という特殊な型が用意されました。

ポイント
  • 値型 T に対して、T? をいう書き方で null 許容型になります。

  • null 許容型は、元となる値型の値か null を保持できる型です。

null 許容型

null 許容型(nullable type)は、値型の型名の後ろに ? を付ける事で、元の型の値または null の値を取れる型になるというものです。 int 型で例に取ると、以下のような書き方が出来ます。

int? x = 123;
int? y = null;

null 許容型にできるのはnull 許容型を除く値型のみです。 (C#の仕様書上は、この「null 許容型を除く値型」を指して、null 非許容型(non-nullable type)と言ったりもします。)

したがって、string? というのは定義できません(参照型には ? を付けれない)。 また、null 許容型をさらに null 許容にすることはできず、 int?? (null 許容型にさらに?を付ける)という書き方はエラーになります。

null 許容型のメンバー

T? という書き方で得られる null 許容型は、 コンパイル結果的には、Nullable<T>構造体(System名前空間) と等価になります。 例えば、以下の2つの変数x と y は全く同じ型の変数になります。

int? x;
Nullable<int> y;

ちなみに、リフレクションで型情報を取り出そうとした場合、null許容型はNullable<T>構造体に見えます。

そして、このNullable<T>構造体は、 HasValueというbool型のプロパティと、 ValueというT型のプロパティを持っています。

Nullable<T> 型のメンバー
戻り値の型 プロパティ名 説明
bool HasValue 有効な(null でない)値を持っていれば true、 値が null ならば false を返します。
T Value 有効な値を返します。 もし、HasValuefalse(値が null)だった場合、 例外 InvalidOperationException 投げます。

また、int? x = 123; という書き方ができることから容易に想像が付くように、 T?型 と T 型の間には暗黙の型変換ができます。 TT? の変換は常に可能で、 以下のようなコードの下2行は等価になります。

int? x;
x = 123;
x = new int?(123); // x = 123; と等価。

その逆、 T?T の変換は、HasValuetrue のときのみ可能で、 HasValuefalse の時には InvalidOperationException がスローされます。

int? x = 123;
int? y = null;
int z;

z = (int)x; // OK。
z = (int)y; // 例外が発生。

null 許容型に対する演算

元となる型 T が持っている演算子は、 そのまま null 許容型 T? に対して利用できます。

Nullable<T> 型に対する演算
単項演算 + ++ - -- ! ~ オペランドも計算結果も共にT型の単項演算子がある場合、T?に対してもその演算子を利用できます。T?型のオペランドが null の場合、計算結果も null になります。
二項演算 + - * / % & | ^ (左右両方の)オペランドも計算結果も共にT型の二項演算子がある場合、T?に対してもその演算子を利用できます。T?型のオペランドのどちらか片方でも null だった場合、計算結果も null になります。 (ただし、bool 型に対する&および|は例外で、 これらに関しては後述します。)
シフト演算 << >> これらも二項演算と同様で、T型の演算子がある場合、T?に対してもその演算子を利用できます。 ただし、シフト演算ですので、右オペランドは int 型です。T?型の左オペランドが null だった場合、計算結果も null になります。
等値演算 == != T型の等値演算がある場合、T?型の等値判定も可能です。T?型の オペランドが左右とも null の場合、比較結果は等しいと判定されます。 また、有効な(non-null の)値と null は等しくありません。 左右ともに有効な値の場合、T型の比較結果と同じになります。
関係演算 < > <= >= T型の比較演算がある場合、T?型の比較も可能です。T?型のオペランドのどちらか片方でも null だった場合、計算結果は false になります。 左右ともに有効な値の場合、T型の比較結果と同じになります。

bool? 型に対する & および | は以下のような結果になります。

bool? に対する &、|
x y x & y x | y
true true true true
true false false true
true null null true
false true false true
false false false false
false null false null
null true null true
null false false null
null null null null

?? 演算

null 許容型には、?? 演算という特殊な演算子を使えます。 この??演算子はnull合体演算子と呼ばれ、 値が null かどうかを判別し、null の場合には別の値を割り当てる演算子です。

// x, y は int? 型の変数
int? z = x ?? y; // x != null ? x : y
int i = z ?? -1; // z != null ? z.Value : -1

coalesce

null合体演算子は、英語では null coalescing operator と言います。

coalesceという名前はSQLの同様の機能から来ているようです。SQLでも、「もし値がnullだったら、別の有効な値を返す」という機能を持ったCOALESCE関数というものがあります。

coalesceの元の英単語の意味は、合体・融合・癒着というような意味です。null coalescing operatorやCOALESCE関数の意味としては、「癒着」が一番近い気がします。SQLが由来ですので、歯抜け(テーブル中のnullの行 = 値が欠けている状態)をパテで埋めるようなイメージでしょうか。

更新履歴

ブログ