連載:[完全版]究極のC#プログラミング

Chapter5 null許容型

川俣 晶
2009/09/28

5.3 null許容型の内部構造

 null許容型は、実際にはNullable<T>構造体(System名前空間)の省略形である。つまり、「int?」は、「System.Nullable<int>」の短縮された表記だということである。

 Nullable<T>構造体は、HasValueプロパティとValueプロパティを持っている。HasValueプロパティは、値を持っていればtrue、持っていなければ……つまり、nullならfalseになる。Valueプロパティは値を持っている場合のみ、その値そのものを提供する。

 しかし、これだけでは使いにくいので、C# 3.0コンパイラは複雑な自動型変換を挿入して対処する

 たとえば、リスト5.2の「a + b」という式はいとも自然に書かれ、素直に計算できるように思える。

using System;

class Program
{
  static void Main(string[] args)
  {
    int? a = 1;
    int b = 2;

    Console.WriteLine(a + b); // 出力:3
  }
}
リスト5.2 null許容型の値を加算に使った例

 しかし、「int?」の実体は「Nullable<int>」なので、足し算の対象にはできない。足し算の対象になる整数値は“その中に入っている”のである。しかも、null許容型ということは、nullだった場合の対処も必要となる。

 上記のリスト5.2をVisual Studio 2008でリリースビルド後、.NET ReflectorでC#として逆コンパイルすると何が起きているのかが見えてくる。

 「a + b」の式に相当する部分は、次のようになっていた。

CS$0$0000.HasValue ? new int?(CS$0$0000.GetValueOrDefault() + CS$0$0001) : null

 つまり、まずnullであるかどうかが判定され、null値であれば計算は実行されることなく式の値はnullで確定する。そうでない場合は、内部に格納された値を使って計算されるわけである。

 一方、null許容型がnullか否かの判定も実は面倒である。次のリスト5.3のコードも一見普通に書かれているように見えるがそうではない。

using System;

class Program
{
  static void Main(string[] args)
  {
    int? a = null;

    if(a == null)
    {
      Console.WriteLine("aはnullです。");
    }
    // 出力:aはnullです。
  }
}
リスト5.3 null許容型がnullか否かの判定

 ここで、「int?」の実体はNullable<int>構造体という“構造体”なので、もちろんnullになることはありえない。この値がnullであるかの判定は、実はHasValueプロパティを使うのが正しい。しかし、「HasValue」というキーワードは、機能を適切に示す良い名前ではあるが、nullであるか否かを判定するプロパティの名前だとは直感的にわかりにくい。

 そこでnull許容型では、「==」や「!=」でnullと値を比較する場合には、あたかもnull許容型の値そのものがnullであるかのように判定式を書くことが可能になっている。それが「if (a == null)」という部分の意味である。

 このリスト5.3は、リスト5.2と同様に.NET Reflectorで逆コンパイルすると、次のようなコードが実際に生成されていることがわかる。

if (!a.HasValue)
「if (a == null)」の逆コンパイル結果


 INDEX
  [完全版]究極のC#プログラミング
  Chapter5 null許容型
    1.5.1 null許容型とは何か?
    2.5.2 なぜnullを入れたいのか?
  3.5.3 null許容型の内部構造
    4.5.4 null合体演算子
    5.5.5 is演算子の挙動に注意
    6.5.6 3値論理型として使用できるbool?型
    7.5.7 nullを許容するとパフォーマンスに影響するか?/null許容への批判/練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間