2016-03-10T00:36:27の更新内容

programming/netfx/nullable/index.wiki.txt

current previous
1,11 1,11
 
${smdncms:title,ヌル許容型}
${smdncms:title,ヌル許容型}
~
${smdncms:header_title,ヌル許容型 (System.Nullable<T>)}
${smdncms:header_title,ヌル許容型 (Nullable)}
 
${smdncms:keywords,ヌル許容型,Nullable型,Nullable<T>}
${smdncms:keywords,ヌル許容型,Nullable型,Nullable<T>}
 
${smdncms:document_versions,codelang=cs,codelang=vb}
${smdncms:document_versions,codelang=cs,codelang=vb}
 

        

        
~
.NET Frameworkの''参照型''では、値が未設定であることを表すために``null``/``Nothing``を使用することができます。 一方``int``/``Integer``などの''値型''では、``null``を代入することはできません。 そのため、未設定や無効な状態であることを表すために``0``(あるいは``-1``や最大値などの値)を代入しておくという手法をとる場合があります。 しかし、``0``という具体的な値を使用してしまうと、未設定であるために``0``なのか、あるいは``0``という有効な値が代入されているのか、これら二つの状態があいまいになるという問題があります。
.NET Frameworkの参照型では値が未設定であることを表すためにnull/Nothingを使用することができます。 一方int/Integerなどの値型ではnullが代入できないため、未設定や無効な値であることを表すために0(あるいは-1や最大値などの値)を代入しておくという手法をとる場合があります。 しかし、0という具体的な値を使用してしまうと、未設定であるために0なのか、あるいは0という値が代入されているのか、二つの状態があいまいになるという問題があります。
 

        

        
~
こういった問題を解消するため、値型に対しても``null``を代入できるようにしたものがヌル許容型(&msdn(netfx,type,System.Nullable`1){Nullable型};)です。 ヌル許容型を使用すると、値型でも``null``が代入されている状態を作り出すことができ、これにより具体的な値が設定されていない状態や無効な状態などを表現することができます。
こういった問題を解消するため、値型にもnullを代入できるようにしたものがヌル許容型(Nullable型)です。 ヌル許容型を使用すると、値型でもnullが代入されている状態、つまり具体的な値が設定されていない状態を表現することができます。
 

        

        
 
#relevantdocs
#relevantdocs
 

        

        
14,22 14,8
 

        

        
 
#relevantdocs-end
#relevantdocs-end
 

        

        
+
#adunit
+

          
+
ヌル許容型に関連して、以下のような演算子・修飾子が導入されています。 詳細については後述しますが、各記号の使い分けやヌル許容型の要点として以下の票をご覧ください。
+

          
+
|*ヌル許容型に関する修飾子・演算子記号
+
|~名前|~記号と使用例|~機能・動作|h
+
|~[[Null許容修飾子>#nullable_type_modifier]]|``int? n``&br;``List<int?> list``&br;``Dim n As Integer?``&br;``Dim list As List(Of Integer?)``|''値型のヌル許容型化''&br;型をヌル許容にする、ヌル許容型を宣言する|
+
|~[[Null合体演算子>#null_coalescing_operator]]|``x = n ?? 3``|''ヌル許容型・参照型の非null化''&br;値を参照して、nullの場合は非null値を設定する|
+
|~[[Null条件演算子>#null_condition_operator]]|``(list = nullとして)``&br;``len = list?.Length``&br;``arr = list?.ToArray()``&br;``len = list?.ToArray()?.Length``&br;``val = list?[0]``|''null参照のショートサーキット''&br;インスタンスや戻り値がnullの場合に、後続するメンバ呼び出しの結果をnullにする|
+

          
+

          
+

          
+

          
 
*ヌル許容型
*ヌル許容型
~
**ヌル許容型の宣言 [#nullable_type_modifier]
ヌル許容型を宣言する場合は、型名の後ろにクエスチョンマーク``?``を付けます。 例えばint型なら``int?``、Integer型なら``Integer?``のようになります。 型名の後ろに付けられる``?``はNull許容修飾子と呼ばれます。 ヌル許容型では、ヌル許容でない通常の型(ヌル非許容型)と同様に具体的な値を代入できるのに加え、``null``/``Nothing``を代入することができます。
+
ヌル許容型を宣言する場合は、型名の後ろにクエスチョンマーク``?``を付けます。 例えばC#のint型なら``int?``、VBのInteger型なら``Integer?``のようになります。 ヌル許容型``int?``では、ヌル許容でない``int``(ヌル非許容型)に対して代入できる値に加えて、``null``/``Nothing``を代入することができるようになります。 ヌル許容型で型名の後ろに付けられる``?``は、''Null許容修飾子''と呼ばれます。
 

        

        
 
#tabpage(codelang=cs,container-title=ヌル許容型変数の宣言)
#tabpage(codelang=cs,container-title=ヌル許容型変数の宣言)
 
#code{{
#code{{
58,7 44,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
整数型などの基本型だけでなく、任意の値型をヌル許容型にすることができます。 独自に定義した構造体の場合も同様に、Null許容修飾子``?``を付けるだけでヌル許容型として宣言することができます。
整数型だけでなく、任意の値型をヌル許容型にすることができます。 独自に定義した構造体の場合も同様にNull許容修飾子``?``を付けるだけでヌル許容型として宣言することができます。
 

        

        
 

        

        
 
#tabpage(codelang=cs,container-title=ヌル許容型変数の宣言)
#tabpage(codelang=cs,container-title=ヌル許容型変数の宣言)
106,87 92,7
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#remarks
ヌル許容型に値が設定されているかどうかを調べるには、``==``演算子, ``!=``演算子(VBでは``Is``演算子, ``IsNot``演算子)を使って``null``/``Nothing``と比較します。
+
構造体をヌル許容にする場合に関して、[[#modify_nullabletype_property]]も参照してください。
+
#remarks-end
+

          
+
**ヌル許容型の配列・コレクション [#collection_of_nullable_types]
+
ヌル許容型は[[配列>programming/netfx/arrays/0_abstract]]や[[List<T>>programming/netfx/collections/2_generic_1_list]]などのコレクションでも用いることができます。 ``int?[]``や``List<int?>``といったように、配列・コレクションの型にNull許容修飾子``?``をつければ、ヌル許容型の配列・コレクションを作成することができます。
+

          
+
配列やコレクションで複数の値を扱う際、要素の一部に''空''の状態(empty)や''未設定''の状態(undefined, uninitialized)を設定したい場合があります。 こういった場合、値型では``null``を用いることができないため、例えば``0``や``-1``などに特別な意味を持たせる場合がありました。 しかし、``0``や``-1``に''空''や''未設定''などの意味を持たせても、それを認識していなければ単なる数値であることにかわりなく、意味が無視され他の数と同列に処理されてしまう可能性があります。 ヌル許容型を用いれば''空''や''未設定''の状態を表すために``null``を用いることができるようになり、左記のような問題を避けることができます。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型の配列・Listを使用する、要素にnullを設定する)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // ヌル許容のint型配列に要素としてnullを格納する
+
    int?[] arr = new int?[] {0, 2, null, 1};
+

          
+
    arr[0] = null; // 配列の要素にnullを設定する
+

          
+
    // ヌル許容のint型Listに要素としてnullを格納する
+
    List<int?> list = new List<int?>() {0, 2, null, 1};
+

          
+
    list.Add(null); // Listの要素としてnullを追加する
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' ヌル許容のInteger型配列に要素としてNothingを格納する
+
    Dim arr?() As Integer = New Integer?() {0, 1, Nothing, 2}
+

          
+
    arr(0) = Nothing ' 配列の要素にNothingを設定する
+

          
+
    ' ヌル許容のint型Listに要素としてNothingを格納する
+
    Dim list As New List(Of Integer?)() From {0, 2, Nothing, 1}
+

          
+
    list.Add(Nothing) ' Listの要素としてNothingを追加する
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#remarks
+
この例ではListの初期化にコレクション初期化子を用いています。 コレクション初期化子を用いたインスタンスの作成については[[programming/netfx/collections/2_generic_1_list#collection_initializer]]を参照してください。
+
#remarks-end
+

          
+

          
+

          
+
VBでヌル許容型の配列を宣言する場合、Null許容修飾子``?``を付ける位置に注意する必要があります。 Null許容修飾子``?``と、配列を表す配列修飾子``()``は常にひと組で記述する必要があります。 変数の側に配列修飾子``()``を付け、型名の後にNull許容修飾子``?``を付けたり、またその逆に付けるとコンパイルエラーとなります。
+

          
+
#code(vb,Null許容修飾子と配列修飾子の適切な記述位置){{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' このようにNull許容修飾子と配列修飾子はセットで付ける必要がある
+
    Dim arr1 As Integer?()
+
    Dim arr2?() As Integer
+

          
+
    ' このようにNull許容修飾子と配列修飾子を別々に付けることはできない
+
    Dim arr3() As Integer?
+
    ' error BC33102: 変数とその型の両方で、Null 許容修飾子 '?' と配列修飾子 '(' および ')' を指定することはできません
+
    Dim arr4? As Integer()
+
    ' error BC33102: 変数とその型の両方で、Null 許容修飾子 '?' と配列修飾子 '(' および ')' を指定することはできません
+
  End Sub
+
End Class
+
}}
+

          
+

          
+

          
+
**値の設定状態のテスト
+
***等号演算子・Is演算子によるテスト
+
ヌル許容型に有効な値(``null``/``Nothing``以外の値)が設定されているかどうかを調べるには、``==``演算子, ``!=``演算子(VBでは``Is``演算子, ``IsNot``演算子)を使って``null``/``Nothing``と比較します。
 

        

        
 
#tabpage(codelang=cs,container-title=ヌル許容型変数に値が設定されているかテストする)
#tabpage(codelang=cs,container-title=ヌル許容型変数に値が設定されているかテストする)
 
#code{{
#code{{
254,9 160,7
 
iには値 '3' が設定されています
iには値 '3' が設定されています
 
}}
}}
 

        

        
~

          
``null``/``Nothing``との比較の他に、&msdn(netfx,member,System.Nullable`1.HasValue){HasValueプロパティ};をチェックする方法もあります。 ヌル許容型に値が設定されている場合、HasValueプロパティはtrueになります。
+
***HasValueプロパティによるテスト [#Nullable.HasValue]
+
``null``/``Nothing``との比較の他に、&msdn(netfx,member,System.Nullable`1.HasValue){HasValueプロパティ};をチェックする方法もあります。 ヌル許容型に値が設定されている場合、HasValueプロパティは``true``になります。
 

        

        
 
#tabpage(codelang=cs,container-title=HasValueプロパティを使ったチェック)
#tabpage(codelang=cs,container-title=HasValueプロパティを使ったチェック)
 
#code{{
#code{{
294,73 198,25
 
iには値 '3' が設定されています
iには値 '3' が設定されています
 
}}
}}
 

        

        
-
参照型の場合とは異なり、ヌル許容型変数に``null``が設定されている場合にHasValueプロパティを参照してもヌル参照(NullReferenceException)にはなりません。
 

        

        
-
また、ヌル許容型から値を取り出してヌル非許容型に代入するには、明示的な型変換を行うか、&msdn(netfx,member,System.Nullable`1.Value){Valueプロパティ};を参照します。
 

        

        
 

        

        
~
参照型の場合とは異なり、ヌル許容型変数に``null``が設定されている場合にHasValueプロパティを参照しても、ヌル参照(&msdn(netfx,type,System.NullReferenceException){NullReferenceException};)にはなりません。 ヌル許容型に``null``が設定されている(値が設定されていない)場合、HasValueプロパティは``false``になります。
#tabpage(codelang=cs,container-title=値の取り出し)
+

          
+
#tabpage(codelang=cs,container-title=nullが代入されているヌル許容型変数のHasValueプロパティを参照する)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    int? i = null; // nullを設定する
    int? i = 3;
+

          
+
    // nullが代入されていてもHasValueプロパティを参照できる(ヌル参照にはならない)
+
    if (i.HasValue)
+
      Console.WriteLine("iには値 '{0}' が設定されています", i);
+
    else
+
      Console.WriteLine("iには値が設定されていません");
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim i As Integer? = Nothing ' Nothingを設定する
+

          
+
    ' Nothingが代入されていてもHasValueプロパティを参照できる(ヌル参照にはならない)
+
    If i.HasValue Then
+
      Console.WriteLine("iには値 '{0}' が設定されています", i)
+
    Else
+
      Console.WriteLine("iには値が設定されていません")
+
    End If
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
 

        

        
~
#prompt(実行結果){{
    int j = (int)i; // 明示的な型変換
~
iには値が設定されていません
    int k = i.Value; // Valueプロパティを使って値を取り出す
+
}}
+

          
+

          
+

          
+

          
+
**値の参照・ヌル非許容型への変換
+
ヌル許容型から値を取り出してヌル非許容型に代入するには、ヌル非許容型への明示的な型変換を行うか、&msdn(netfx,member,System.Nullable`1.Value){Valueプロパティ};を参照します。 明示的な型変換を行う場合、[[拡大変換となる型変換>programming/netfx/conversion/0_basetype]](``int``→``long``、``byte``→``int``など)であれば型の異なるヌル非許容型への代入を行うこともできます。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型に代入されている値の取り出し)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    int? i = 3; // ヌル許容型
+

          
+
    int j = (int)i; // 明示的な型変換によって値を取り出す
+
    long k = (long)i; // 拡大変換となる型変換で値を取り出す
+
    int l = i.Value; // Valueプロパティを使って値を取り出す
 

        

        
 
    Console.WriteLine(j);
    Console.WriteLine(j);
 
    Console.WriteLine(k);
    Console.WriteLine(k);
+
    Console.WriteLine(l);
 
  }
  }
 
}
}
 
}}
}}
370,15 226,13
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    Dim i As Integer? = 3 ' ヌル許容型
    Dim i As Integer? = 3
 

        

        
 
    Dim j As Integer = CInt(i) ' 明示的な型変換
    Dim j As Integer = CInt(i) ' 明示的な型変換
~
    Dim k As Long = CLng(i) ' 拡大変換となる型変換で値を取り出す
    Dim k As Integer = i.Value ' Valueプロパティを使って値を取り出す
+
    Dim l As Integer = i.Value ' Valueプロパティを使って値を取り出す
 

        

        
 
    Console.WriteLine(j)
    Console.WriteLine(j)
 
    Console.WriteLine(k)
    Console.WriteLine(k)
+
    Console.WriteLine(l)
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
387,17 241,9
 
#prompt(実行結果){{
#prompt(実行結果){{
 
3
3
 
3
3
+
3
 
}}
}}
 

        

        
~
#remarks
値が設定されていない状態でヌル非許容型へのキャストまたはValueプロパティを参照すると例外&msdn(netfx,type,System.InvalidOperationException){InvalidOperationException};がスローされます。 (&msdn(netfx,type,System.NullReferenceException){NullReferenceException};ではないので注意)
+
Valueプロパティは取得専用のため、このプロパティを使って値を設定することはできません。 ヌル許容型への値を設定は、通常の変数と同様に直接代入して行います。
+
#remarks-end
+

          
+

          
+

          
+

          
+
値が設定されていない状態で、ヌル非許容型へのキャストまたはValueプロパティを参照すると例外&msdn(netfx,type,System.InvalidOperationException){InvalidOperationException};がスローされます。 (&msdn(netfx,type,System.NullReferenceException){NullReferenceException};ではないので注意)
 

        

        
 
#tabpage(codelang=cs,container-title=設定されていない場合での値の取得)
#tabpage(codelang=cs,container-title=設定されていない場合での値の取得)
 
#code{{
#code{{
431,19 277,16
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
ハンドルされていない例外: System.InvalidOperationException: Null 許容のオブジェクトには値を指定しなければなりません。
Unhandled Exception:
~
   場所 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
System.InvalidOperationException: Nullable object must have a value.
~
   場所 Sample.Main()
  at System.Nullable`1[System.Int32].get_Value () [0x00000] in <filename unknown>:0 
-
  at Sample.Main () [0x00000] in <filename unknown>:0 
 
}}
}}
 

        

        
-
この他、C#では値の取り出しにヌル合体演算子``??``を使用することができます。 これはヌル許容型の持つ値を参照する際、値が``null``だった場合に設定する値を指定する演算子です。 三項演算子``?:``と似ていますが、よりシンプルに記述できます。 VBではこれに相当する演算子は用意されていませんが、二項形式の``If``演算子を使用することで同様のことができます。 ([[programming/vb.net/operator_logical#IfOperator]])
 

        

        
~
***Null合体演算子・If演算子による値の非null化 [#null_coalescing_operator]
#tabpage(codelang=cs,container-title=ヌル合体演算子)
~
C#では値の取り出しに''Null合体演算子''``??``を使用することもできます。 この演算子は、ヌル許容型の持つ値を参照する際、値が``null``だった場合に代替として用いる非null値を指定する演算子です。 三項演算子``?:``と似ていますが、よりシンプルに記述できます。 例えばヌル許容型変数``&var{a};``に対して``x = a ?? 16``という式を記述した場合、``&var{a};``が値を持っている場合はその値、持っていない場合は``16``が``&var{x};``に代入されます。
#code{{
+

          
+
VBではこれに相当する演算子は用意されていませんが、二項形式の``If``演算子を使用することで同様のことができます。 (詳細:[[programming/vb.net/operator_logical#IfOperator]])
+

          
+
#tabpage(codelang=cs)
+
#code(cs,Null合体演算子による値の参照){{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
453,10 296,10
 
    int? b = 3;
    int? b = 3;
 

        

        
 
    int x = a ?? 16; // aはnullなので、xには16が代入される
    int x = a ?? 16; // aはnullなので、xには16が代入される
~
    int y = b ?? 16; // bは3(値を持っている)なので、yには3が代入される
    int y = b ?? 16; // bは3(値を持つ)なので、yには3が代入される
 

        

        
~
    Console.WriteLine("x = {0}", x);
    Console.WriteLine(x);
~
    Console.WriteLine("y = {0}", y);
    Console.WriteLine(y);
 

        

        
 
    // 三項演算子を使って記述すると次のようになる
    // 三項演算子を使って記述すると次のようになる
 
    int xx = a.HasValue ? a.Value : 16;
    int xx = a.HasValue ? a.Value : 16;
465,7 308,7
 
}
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
~
#code(vb,二項形式のIf演算子による値の参照){{
#code{{
 
Imports System
Imports System
 

        

        
 
Class Sample
Class Sample
474,12 317,12
 
    Dim b As Integer? = 3
    Dim b As Integer? = 3
 

        

        
 
    Dim x As Integer = If(a, 16) ' aはNothingなので、xには16が代入される
    Dim x As Integer = If(a, 16) ' aはNothingなので、xには16が代入される
~
    Dim y As Integer = If(b, 16) ' bは3(値を持っている)なので、yには3が代入される
    Dim y As Integer = If(b, 16) ' bは3(値を持つ)なので、yには3が代入される
 

        

        
~
    Console.WriteLine("x = {0}", x)
    Console.WriteLine(x)
~
    Console.WriteLine("y = {0}", y)
    Console.WriteLine(y)
 

        

        
~
    ' 三項形式のIf演算子を使って記述すると次のようになる
    ' 三項演算子を使って記述すると次のようになる
 
    Dim xx As Integer = If(a.HasValue, a.Value, 16)
    Dim xx As Integer = If(a.HasValue, a.Value, 16)
 
    Dim yy As Integer = If(b.HasValue, b.Value, 16)
    Dim yy As Integer = If(b.HasValue, b.Value, 16)
 
  End Sub
  End Sub
488,156 331,132
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
x = 16
16
~
y = 3
3
 
}}
}}
 

        

        
~
Null合体演算子を用いることにより、値が``null``だった場合に別の値を代入するといった操作を、if文による条件分岐や三項演算子``?:``を用いずに記述することができます。
ヌル合体演算子に似たものとして&msdn(netfx,member,System.Nullable`1.GetValueOrDefault){GetValueOrDefaultメソッド};があります。 このメソッドは、ヌル許容型に値が設定されている場合はその値を、設定されていない場合は型のデフォルト値(``0``または``0``に相当する値)を返します。 値が設定されていない場合でもデフォルト値を使って処理を継続してもよい場合などに使用することができます。
 

        

        
~
#remarks
#tabpage(codelang=cs,container-title=GetValueOrDefaultメソッド)
~
これと同様の操作は後述の[[GetValueOrDefaultメソッド>#Nullable.GetValueOrDefault]]を使うことによっても行うことができます。
#code{{
+
#remarks-end
+

          
+
****参照型でのNull合体演算子の使用
+
Null合体演算子は参照型に対しても用いることができます。 ヌル許容型に対して用いる場合と同様、第一項が``null``だった場合は第二項の値が用いられます。 VBの二項形式のIf演算子も参照型に対して同様に動作します。
+

          
+
#tabpage(codelang=cs)
+
#code(cs,参照型に対してNull合体演算子を用いる){{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    string a = null;
    int? a = null;
~
    string b = "foo";
    int? b = 3;
 

        

        
~
    string x = a ?? "(null)"; // aはnullなので、xには"(null)"が代入される
    int x = a.GetValueOrDefault(); // aはnullなので、xにはデフォルト値0が代入される
~
    string y = b ?? "(null)"; // bは"foo"(値を持っている)なので、yには"foo"が代入される
    int y = b.GetValueOrDefault(); // bは3(値を持つ)なので、yには3が代入される
 

        

        
~
    Console.WriteLine("x = {0}", x);
    Console.WriteLine(x);
~
    Console.WriteLine("y = {0}", y);
    Console.WriteLine(y);
 
  }
  }
 
}
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
~
#code(vb,参照型に対して二項形式のIf演算子を用いる){{
#code{{
 
Imports System
Imports System
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    Dim a As String = Nothing
    Dim a As Integer? = Nothing
~
    Dim b As String = "foo"
    Dim b As Integer? = 3
 

        

        
~
    Dim x As String = If(a, "(Nothing)") ' aはNothingなので、xには"(Nothing)"が代入される
    Dim x As Integer = a.GetValueOrDefault() ' aはNothingなので、xにはデフォルト値0が代入される
~
    Dim y As String = If(b, "(Nothing)") ' bは"foo"(値を持っている)なので、yには"foo"が代入される
    Dim y As Integer = b.GetValueOrDefault() ' bは3(値を持つ)なので、yには3が代入される
 

        

        
~
    Console.WriteLine("x = {0}", x)
    Console.WriteLine(x)
~
    Console.WriteLine("y = {0}", y)
    Console.WriteLine(y)
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
x = (null)
0
~
y = foo
3
 
}}
}}
 

        

        
~
****Null合体演算子と他の型への変換
#remarks
~
Null合体演算子では、第一項・第二項ともに同一の型である必要があります(Option Strict Onの場合はVBのIf演算子も同様)。 例えば、次の例のようにヌル許容型の値を型変換するような場合、``null``だった場合の値をにはNull合体演算子単体では処理できません。 この場合はif文や三項演算子を用いるか、あるいは[[Null条件演算子>#null_condition_operator]]を用います。
型のデフォルト値については[[programming/netfx/basic_types/0_characteristics#DefaultValue]]を参照してください。
-
#remarks-end
-

          
-
**ヌル許容型と演算
-
ヌル非許容型での演算と同様、ヌル許容型でも演算子を使って加算などの演算を行うことができます。 ただし、演算子の項のどちらか一方がnullの場合、演算結果もnullとなります。
 

        

        
~
#tabpage(codelang=cs)
#tabpage(codelang=cs,container-title=ヌル許容型と演算)
~
#code(cs,値の型を変換するような場面でNull合体演算子を使用したい){{
#code{{
 
using System;
using System;
+
using System.Linq;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    // この配列をカンマ区切りで"0, 1, (empty), 2"と出力したい
    int? x = 3;
+
    int?[] arr = new int?[] {0, 1, null, 2};
 

        

        
~
    // 前提: nullは空の文字列になるため、"0, 1, , 2"と表示されてしまう
    x = x + 1; // xには4が代入される
+
    // (nullの場合は"(empty)"と表示したい)
+
    Console.WriteLine(string.Join(", ", arr));
+

          
+
    // Null合体演算子では異なる型を指定できないのでコンパイルエラーとなる
+
    //Console.WriteLine(string.Join(", ", arr.Select(val => val ?? "(empty)")));
+
    // error CS0019: 演算子 '??' を 'int?' と 'string' 型のオペランドに適用することはできません。
+

          
+
    // nullが設定されたヌル許容型に対してToString()を呼び出すと空の文字列(=nullではない)になるため、
+
    // Null合体演算子の第二項が使用されない
+
    Console.WriteLine(string.Join(", ", arr.Select(val => val.ToString() ?? "(empty)")));
 

        

        
~
    // 'Null条件演算子'と組み合わせて用いると、目的の動作となる
    Console.WriteLine(x);
~
    Console.WriteLine(string.Join(", ", arr.Select(val => val?.ToString() ?? "(empty)")));

          
-
    int? y = null;
-

          
-
    x = y + 1; // yがnullのため、xにはnullが代入される
-

          
-
    Console.WriteLine(x.HasValue);
 
  }
  }
 
}
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
~
#code(vb,値の型を変換するような場面でIf演算子を使用したい){{
#code{{
+
Option Strict On
+

          
 
Imports System
Imports System
+
Imports System.Linq
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    ' この配列をカンマ区切りで"0, 1, (empty), 2"と出力したい
    Dim x As Integer? = 3
~
    Dim arr?() As Integer = New Integer?() {0, 1, Nothing, 2}

          
-
    x = x + 1 ' xには4が代入される
 

        

        
~
    ' 前提: Nothingは空の文字列になるため、"0, 1, , 2"と表示されてしまう
    Console.WriteLine(x)
~
    ' (Nothingの場合は"(empty)"と表示したい)

          
~
    Console.WriteLine(String.Join(", ", arr))
    Dim y As Integer? = Nothing
+

          
+
    ' Option Strict Onの場合、If演算子では異なる型を指定できないのでコンパイルエラーとなる
+
    'Console.WriteLine(String.Join(", ", arr.Select(Function(val) If(val, "(empty)"))))
+
    ' error BC33110: バイナリ 'If' 演算子の 1 番目と 2 番目のオペランドの共通型を推論できません
+

          
+
    ' Nothingが設定されたヌル許容型に対してToString()を呼び出すと空の文字列(=Nothingではない)になるため、
+
    ' If演算子の第二項が使用されない
+
    Console.WriteLine(String.Join(", ", arr.Select(Function(val) If(val.ToString(), "(empty)"))))
 

        

        
~
    ' "Nothing条件演算子"と組み合わせて用いると、目的の動作となる
    x = y + 1 ' yがNothingのため、xにはNothingが代入される
~
    Console.WriteLine(String.Join(", ", arr.Select(Function(val) If(val?.ToString(), "(empty)"))))

          
-
    Console.WriteLine(x.HasValue)
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
0, 1, , 2
4
~
0, 1, , 2
False
+
0, 1, (empty), 2
 
}}
}}
 

        

        
+
''Null条件演算子''については[[#null_condition_operator]]で別途解説します。
 

        

        
-
*Nullable<T>構造体
-
ヌル許容型の実体は&msdn(netfx,type,System.Nullable`1){Nullable<T>構造体};です。 そのため、次のようにNullable構造体を使ってヌル許容型の変数を宣言することもできます。 ヌル許容型の&msdn(netfx,member,System.Nullable`1.Value){Value};や&msdn(netfx,member,System.Nullable`1.HasValue){HasValue};などのプロパティはNullable構造体によって提供されます。
 

        

        
~

          
#tabpage(codelang=cs,container-title=Nullable<T>構造体とヌル許容型)
+
***GetValueOrDefaultメソッドによる値の非null化 [#Nullable.GetValueOrDefault]
+
[[Null合体演算子>#null_coalescing_operator]]に似たものとして、&msdn(netfx,member,System.Nullable`1.GetValueOrDefault){GetValueOrDefaultメソッド};があります。 このメソッドは、ヌル許容型に値が設定されている場合はその値を、設定されていない場合は型のデフォルト値(``0``または``0``に相当する値)を返します。 ``0``以外の値をデフォルト値としたい場合は、引数でデフォルト値として使用する値を指定することもできます。 戻り値はヌル非許容型となるため、デフォルト値として``null``/``Nothing``を指定することはできません。
+

          
+
このメソッドは、ヌル許容型に値が設定されていない場合はデフォルト値を使って処理を継続させたい場合などに使用することができます。
+

          
+
#tabpage(codelang=cs,container-title=GetValueOrDefaultメソッドを使ってnullの場合はデフォルト値を用いて値を取得する)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    int? a = null;
    // 以下の二つはどちらもNullable<int>を宣言している
~
    int? b = null;
    int? a = 1;
~
    int? c = 3;
    Nullable<int> b = 2;
-

          
-
    Console.WriteLine(a.Value);
-
    Console.WriteLine(b.Value);
-

          
-
    a = null;
-
    b = null;
 

        

        
~
    int x = a.GetValueOrDefault();   // aはnullなので、xにはデフォルト値0が代入される
    Console.WriteLine(a.HasValue);
~
    int y = b.GetValueOrDefault(-1); // bはnullなので、yにはデフォルト値として-1が代入される
    Console.WriteLine(b.HasValue);
+
    int z = c.GetValueOrDefault(-1); // cは3(値を持っている)なので、zにはcの値=3が代入される
+

          
+
    Console.WriteLine("x = {0}", x);
+
    Console.WriteLine("y = {0}", y);
+
    Console.WriteLine("z = {0}", z);
 
  }
  }
 
}
}
 
}}
}}
647,97 466,89
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    Dim a As Integer? = Nothing
    ' 以下の二つはどちらもNullable(Of Integer)を宣言している
~
    Dim b As Integer? = Nothing
    Dim a As Integer? = 1
~
    Dim c As Integer? = 3
    Dim b As Nullable(Of Integer) = 2
-

          
-
    Console.WriteLine(a.Value)
-
    Console.WriteLine(b.Value)
-

          
-
    a = Nothing
-
    b = Nothing
 

        

        
~
    Dim x As Integer = a.GetValueOrDefault()   ' aはNothingなので、xにはデフォルト値0が代入される
    Console.WriteLine(a.HasValue)
~
    Dim y As Integer = b.GetValueOrDefault(-1) ' bはNothingなので、yにはデフォルト値として-1が代入される
    Console.WriteLine(b.HasValue)
+
    Dim z As Integer = c.GetValueOrDefault(-1) ' cは3(値を持っている)なので、zにはcの値=3が代入される
+

          
+
    Console.WriteLine("x = {0}", x)
+
    Console.WriteLine("y = {0}", y)
+
    Console.WriteLine("z = {0}", z)
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
x = 0
1
~
y = -1
2
~
z = 3
False
-
False
 
}}
}}
 

        

        
~
#remarks
言語が直接ヌル許容型をサポートしていない場合でも、ジェネリクスを使用できる言語であればNullable構造体を使用してヌル許容型を作成・使用することができます。
+
型のデフォルト値については[[programming/netfx/basic_types/0_characteristics#DefaultValue]]を参照してください。
+
#remarks-end
 

        

        
~
#remarks
Nullable構造体の型引数``T``には値型のみを指定できます。 従って、参照型をベースにしたヌル許容型を作成することはできません。
+
デフォルト値を``null``として処理を継続させたいような場合は、[[Null条件演算子>#null_condition_operator]]を使うことができます。
+
#remarks-end
 

        

        
~
**ヌル許容型での演算
#tabpage(codelang=cs,container-title=Nullable<T>構造体とヌル許容型)
+
ヌル許容型に対しても、ヌル非許容型での演算と同様に加算などの演算を行うことができます。 ただし、演算子の項のどちらか一方が``null``の場合は、演算結果も``null``となります。 これに従い、演算結果も必然的にヌル許容型となります。 そのため、ヌル許容型を項に含む演算結果をヌル非許容型に代入することはできません。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型が値を持つ場合の演算結果)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    int? a = 3;
    // 値型をベースにしたヌル許容型
~
    int? x = a + 1; // xには4が代入される
    int? i = null;
-
    bool? b = null;
-
    Nullable<double> d = null;
 

        

        
~
    Console.WriteLine(x);
    // 参照型をベースにしたヌル許容型を作成することはできない
~

          
    string? s = null;
~
    // ヌル許容型の演算結果をヌル非許容型へ代入することはできない
    // error CS0453: 型 'string' は、ジェネリック型のパラメーター 'T'、またはメソッド 'System.Nullable<T>' として使用するために、Null非許容の値型でなければなりません
~
    // (項のどちらかがnullであれば演算結果がnullとなるため)
    Nullable<object> o = null;
~
    //int y = a + 1;
    // error CS0453: 型 'object' は、ジェネリック型のパラメーター 'T'、またはメソッド 'System.Nullable<T>' として使用するために、Null非許容の値型でなければなりません
+
    // error CS0266: 型 'int?' を 'int' に暗黙的に変換できません。明示的な変換が存在します。(cast が不足していないかどうかを確認してください)
 
  }
  }
 
}
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
 
#code{{
#code{{
+
Option Strict On
+

          
 
Imports System
Imports System
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    Dim a As Integer? = 3
    ' 値型をベースにしたヌル許容型
~
    Dim x As Integer? = a + 1 ' xには4が代入される
    Dim i As Integer? = Nothing
-
    Dim b As Boolean = Nothing
-
    Dim d As Double = Nothing
 

        

        
~
    Console.WriteLine(x)
    ' 参照型をベースにしたヌル許容型を作成することはできない
~

          
    Dim s As String? = Nothing
~
    ' ヌル許容型の演算結果をヌル非許容型へ代入することはできない
    ' error BC33101: 'Nullable' または Null 許容修飾子 '?' と共に使用するためには、型 'String' は 'Structure' に制約されている値型または型引数である必要があります
~
    ' (項のどちらかがNothingであれば演算結果がNothingとなるため)
    Dim o As Nullable(Of Object) = Nothing
~
    'Dim y As Integer = a + 1
    ' error BC33101: 'Nullable' または Null 許容修飾子 '?' と共に使用するためには、型 'Object' は 'Structure' に制約されている値型または型引数である必要があります
+
    ' error BC30512: Option Strict On では、'Integer?' から 'Integer' への暗黙的な変換はできません
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
~
#prompt(実行結果){{
**ヌル許容型と型情報
~
4
ヌル許容型で&msdn(netfx,member,System.Object.GetType){GetTypeメソッド};を使用して型情報を取得しようとすると、元になった型の型情報が返されます。 例えば``int?``では``System.Nullable<System.Int32>``ではなく``System.Int32``が返されます。
+
}}
+

          
 

        

        
~

          
#tabpage(codelang=cs,container-title=ヌル許容型に対するGetType)
+
#tabpage(codelang=cs,container-title=ヌル許容型が値を持たない場合の演算結果)
 
#code{{
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    int? a = null;
    // ヌル許容型
~
    int? x = a + 1; // aはnullのため、xにはnullが代入される
    int? x = 0;
 

        

        
~
    Console.WriteLine(x.HasValue);
    Console.WriteLine(x.GetType());
 
  }
  }
 
}
}
 
}}
}}
747,83 558,49
 

        

        
 
Class Sample
Class Sample
 
  Public Shared Sub Main()
  Public Shared Sub Main()
~
    Dim a As Integer? = Nothing
    ' ヌル許容型
~
    Dim x As Integer? = a + 1 ' aはNothingのため、xにはNothingが代入される
    Dim x As Integer? = 0
 

        

        
~
    Console.WriteLine(x.HasValue)
    Console.WriteLine(x.GetType())
 
  End Sub
  End Sub
 
End Class
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
 
#prompt(実行結果){{
#prompt(実行結果){{
~
False
System.Int32
 
}}
}}
 

        

        
-
またC#では、ヌル許容型を``is``演算子で比較する場合、元の型が同じであればヌル許容型でもヌル非許容型でも同一の型とみなされます。
 

        

        
~
**ヌル許容型でのToStringメソッドによる文字列化
#code(cs,ヌル許容型とis演算子での比較){{
+
ヌル許容型ではToStringメソッドを呼び出すことはできますが、引数で書式を指定することはできません。 これは、ヌル許容型を構成する&msdn(netfx,type,System.Nullable`1){Nullable<T>構造体};の&msdn(netfx,member,System.Nullable`1.ToString){ToStringメソッド};には書式を指定するバージョンがないためです。 書式と同様、カルチャなどの書式プロバイダを指定することもできません。
+

          
+
そのため、書式を指定してヌル許容型の値を文字列化したい場合は、&msdn(netfx,member,System.String.Format){String.Formatメソッド};を使うか、Valueプロパティを参照してその値に対してToStringメソッドを呼び出す必要があります。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型で書式を指定して文字列化する)
+
#code{{
 
using System;
using System;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
 
  {
  {
~
    int i = 3;
    // ヌル許容型
~
    int? ni = 3;
    int? x = 0;
 

        

        
~
    // 有効桁数4の自然数(N)として文字列化したい
    // 以下のどちらもtrueとなる
~
    Console.WriteLine(i.ToString("N4"));
    if (x is int?)
~
    Console.WriteLine(ni.ToString("N4")); // ヌル許容型では書式を指定したToStringができない
      Console.WriteLine("x is int?");
+
    // error CS1501: 引数を '1' 個指定できる、メソッド 'ToString' のオーバーロードはありません。
 

        

        
~
    // この場合、String.Formatメソッドによって文字列化する必要がある
    if (x is int)
~
    Console.WriteLine(string.Format("{0:N4}", ni));
      Console.WriteLine("x is int");
+

          
+
    // あるいは、Valueプロパティの値に対してToStringメソッドを呼び出す
+
    Console.WriteLine(ni.Value.ToString("N4"));
 
  }
  }
 
}
}
 
}}
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
 

        

        
~
Class Sample
#prompt(実行結果){{
~
  Public Shared Sub Main()
x is int?
~
    Dim i As Integer = 3
x is int
+
    Dim ni As Integer? = 3
+

          
+
    ' 有効桁数4の自然数(N)として文字列化したい
+
    Console.WriteLine(i.ToString("N4"))
+
    Console.WriteLine(ni.ToString("N4")) ' ヌル許容型では書式を指定したToStringができない
+
    ' error BC30512: Option Strict On では、'String' から 'Integer' への暗黙的な変換はできません
+

          
+
    ' この場合、String.Formatメソッドによって文字列化する必要がある
+
    Console.WriteLine(String.Format("{0:N4}", ni))
+

          
+
    ' あるいは、Valueプロパティの値に対してToStringメソッドを呼び出す
+
    Console.WriteLine(ni.Value.ToString("N4"))
+
  End Sub
+
End Class
 
}}
}}
+
#tabpage-end
+

          
+
#remarks
+
Nullable<T>構造体については後述の[[#System.Nullable]]を参照してください。
+
#remarks-end
+

          
+
#remarks
+
書式を指定した文字列化に関しては[[programming/netfx/string_formatting/0_formatstrings]]、書式プロバイダについては[[programming/netfx/locale/1_infoes]]または[[programming/netfx/string_formatting/1_formatters]]を参照してください。
+
#remarks-end
 

        

        
-
C#・VBでは、型がヌル許容型かどうかを調べる手段は言語の機能としては用意されていません。
 

        

        
~
**ヌル許容型構造体でのフィールド・プロパティの値の変更 [#modify_nullabletype_property]
**ヌル許容型構造体でのフィールド・プロパティの値の変更
~
次の例のように、ヌル許容型の構造体でフィールド・プロパティの値を変更しようとした場合、コンパイルエラーとなります。
例えば次のようにヌル許容型の構造体でフィールド・プロパティの値を変更しようとした場合、コンパイルエラーとなります。
 

        

        
 
#tabpage(codelang=cs,container-title=ヌル許容型構造体でのフィールドの参照)
#tabpage(codelang=cs,container-title=ヌル許容型構造体でのフィールドの参照)
 
#code{{
#code{{
932,648 709,4
 

        

        
 

        

        
 

        

        
+

          
+
*Null条件演算子 [#null_condition_operator]
+
ヌル許容型や参照型のメソッドを呼び出す場合など、ヌル参照を避ける目的で次のように事前にif文などによるチェックを行う場面が多くあります。 C# 6.0およびVisual Basic 2015以降では''Null条件演算子''が新たに導入されていて、このようなヌルチェックの処理をシンプルに記述することができます。
+

          
+
#column
+
#tabpage(codelang=cs,container-title=Null条件演算子によるヌル参照の回避)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    int[] arr = null;
+

          
+
    // 配列の長さを取得して変数lenに代入する
+
    // (配列がnullの場合はnullが代入される)
+
    int? len = arr?.Length;
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim arr() As Integer = Nothing
+

          
+
    ' 配列の長さを取得して変数lenに代入する
+
    ' (配列がNothingの場合はNothingが代入される)
+
    Dim len As Integer? = arr?.Length
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+
#column
+
#tabpage(codelang=cs,container-title=if文によるヌル参照の回避)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    int[] arr = null;
+

          
+
    // 配列の長さを取得して変数lenに代入する
+
    // (配列がnullの場合は0を代入する)
+
    int len;
+

          
+
    if (arr == null)
+
      len = 0;
+
    else
+
      len = arr.Length;
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim arr() As Integer = Nothing
+

          
+
    ' 配列の長さを取得して変数lenに代入する
+
    ' (配列がnullの場合は0を代入する)
+
    Dim len As Integer
+

          
+
    If arr Is Nothing Then
+
      len = 0
+
    Else
+
      len = arr.Length
+
    End If
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+
#column-end
+

          
+
このように''Null条件演算子''は、プロパティ参照やメソッド呼び出しなど、メンバへのアクセスを行おうとした場合に``null``かどうかのチェックを行います。 この時、``null``だった場合は呼び出しを行わず、``null``を結果として返します。 Null条件演算子を記述した場合でも、呼び出し元(Null条件演算子の左項)が``null``でなければ通常のメンバアクセスと同様に扱われます。
+

          
+
またNull条件演算子を使う場合、その結果はメンバへのアクセスによって得られる値(プロパティの値・メソッドの戻り値)か、あるいは``null``のどちらかになります。 そのため、必然的にNull条件演算子の左辺は参照型あるいはヌル許容型となります。
+

          
+
#tabpage(codelang=cs,container-title=Null条件演算子とヌル値・非ヌル値での動作)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    int[] arr = new int[] {0, 1, 2, 3, 4};
+

          
+
    // 変数にnull以外が代入されている場合
+
    int? len1 = arr?.Length; // arrはnullではないため、len1にはarr.Lengthの値が代入される
+

          
+
    Console.WriteLine("len1 = {0}", len1);
+

          
+
    // 変数にnullが代入されている場合
+
    arr = null;
+

          
+
    int? len2 = arr?.Length; // arrはnullのためLengthプロパティは参照されず、len2にはnullが代入される
+

          
+
    Console.WriteLine("len2 = {0}", len2);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim arr() As Integer = New Integer() {0, 1, 2, 3, 4}
+

          
+
    ' 変数にNothing以外が代入されている場合
+
    Dim len1 As Integer? = arr?.Length ' arrはnullではないため、len1にはarr.Lengthの値が代入される
+

          
+
    Console.WriteLine("len1 = {0}", len1)
+

          
+
    ' 変数にNothingが代入されている場合
+
    arr = Nothing
+

          
+
    Dim len2 As Integer? = arr?.Length ' arrはnullのためLengthプロパティは参照されず、len2にはnullが代入される
+

          
+
    Console.WriteLine("len2 = {0}", len2)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
len1 = 5
+
len2 = 
+
}}
+

          
+

          
+

          
+

          
+
Null条件演算子は、メソッド・プロパティ・インデクサなどの参照に前置することができます。 また、戻り値を持たないメソッドの呼び出しにも使うことができます。 ただし、インデクサの設定に用いることはできません。
+

          
+
#tabpage(codelang=cs,container-title=Null条件演算子によるメソッド・プロパティ・インデクサの参照)
+
#code{{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    List<int> list = null;
+

          
+
    int? len = list?.Count; // プロパティ参照
+

          
+
    int? index = list?.IndexOf(2); // メソッド呼び出し
+

          
+
    list?.Clear(); // 戻り値のないメソッドの呼び出し
+

          
+
    int? e = list?[0]; // インデクサ参照
+

          
+
    // インデクサの設定ではNull条件演算子を用いることはできない
+
    //list?[0] = 10;
+
    // error CS0131: 代入式の左辺には変数、プロパティ、またはインデクサーを指定してください。
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim list As List(Of Integer) = Nothing
+

          
+
    Dim len As Integer? = list?.Count ' プロパティ参照
+

          
+
    Dim index As Integer? = list?.IndexOf(2) ' メソッド呼び出し
+

          
+
    list?.Clear() ' 戻り値のないメソッドの呼び出し
+

          
+
    Dim e As Integer? = list?(0) ' インデクサ参照
+

          
+
    ' インデクサの設定ではNull条件演算子を用いることはできない
+
    'list?(0) = 10
+
    ' error BC30068: Expression は値であるため、代入式のターゲットにすることはできません。
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+

          
+

          
+

          
+
さらに、メソッドチェイン(戻り値から連続するメソッド呼び出し)においてもNull条件演算子を用いることができます。 この場合、呼び出し元や戻り値が``null``となった時点で結果は``null``に確定し、それ以降の呼び出しが行われなくなります(''ショートサーキット'')。
+

          
+
#tabpage(codelang=cs,container-title=Null条件演算子を使ってnullを扱えるメソッドチェインを記述する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    string str = null;
+

          
+
    // メソッドチェインでNull条件演算子を使う
+
    int? len = str?.Trim()?.Substring(5)?.Length;
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim str As String = Nothing
+

          
+
    ' メソッドチェインでNull条件演算子を使う
+
    Dim len As Integer? = str?.Trim()?.Substring(5)?.Length
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#remarks
+
演算子によって``null``を後続に伝播させることができるとも捉えることができるため、Null条件演算子の導入前はNull伝播演算子(null propagating operator)とも呼ばれていました。
+
#remarks-end
+

          
+

          
+

          
+
このほか、イベントの発生にもNull条件演算子を用いることができます。 イベントの発生は、Null条件演算子によって記述がシンプルになる好例です。
+

          
+
#code(cs,Null条件演算子を使ってイベントを発生させる){{
+
using System;
+
using System.ComponentModel;
+

          
+
class C {
+
  public event PropertyChangedEventHandler PropertyChanged;
+

          
+
  protected virtual void RaisePropertyChanged1(string propertyName)
+
  {
+
    // イベントPropertyChangedを発生させる (if文によるヌルチェック)
+
    var ev = this.PropertyChanged;
+

          
+
    if (ev != null)
+
      ev(this, new PropertyChangedEventArgs(propertyName));
+
  }
+

          
+
  protected virtual void RaisePropertyChanged2(string propertyName)
+
  {
+
    // イベントPropertyChangedを発生させる (Null条件演算子によるnullのショートサーキット)
+
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+
  }
+
}
+
}}
+

          
+
#remarks
+
イベントの発生については[[programming/netfx/delegate/1_events]]、INotifyPropertyChangedとPropertyChangedEventHandlerによるプロパティ変更の通知については[[programming/netfx/property#INotifyPropertyChanged]]で解説しています。
+
#remarks-end
+

          
+

          
+

          
+

          
+

          
+
*Nullable<T>構造体 [#System.Nullable]
+
ヌル許容型の実体は&msdn(netfx,type,System.Nullable`1){Nullable<T>構造体};です。 そのため、次のようにNullable構造体を使ってヌル許容型の変数を宣言することもできます。 ヌル許容型の&msdn(netfx,member,System.Nullable`1.Value){Value};や&msdn(netfx,member,System.Nullable`1.HasValue){HasValue};などのプロパティはNullable構造体によって提供されます。
+

          
+
#tabpage(codelang=cs,container-title=Nullable<T>構造体とヌル許容型)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 以下の二つはどちらもNullable<int>を宣言している
+
    int? a = 1;
+
    Nullable<int> b = 2;
+

          
+
    Console.WriteLine(a.Value);
+
    Console.WriteLine(b.Value);
+

          
+
    a = null;
+
    b = null;
+

          
+
    Console.WriteLine(a.HasValue);
+
    Console.WriteLine(b.HasValue);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 以下の二つはどちらもNullable(Of Integer)を宣言している
+
    Dim a As Integer? = 1
+
    Dim b As Nullable(Of Integer) = 2
+

          
+
    Console.WriteLine(a.Value)
+
    Console.WriteLine(b.Value)
+

          
+
    a = Nothing
+
    b = Nothing
+

          
+
    Console.WriteLine(a.HasValue)
+
    Console.WriteLine(b.HasValue)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
1
+
2
+
False
+
False
+
}}
+

          
+
言語が直接ヌル許容型をサポートしていない場合でも、ジェネリクスを使用できる言語であればNullable構造体を使用してヌル許容型を作成・使用することができます。
+

          
+

          
+

          
+
Nullable構造体の型引数``T``には値型のみを指定できます。 従って、参照型をベースにしたヌル許容型を作成することはできません。
+

          
+
#tabpage(codelang=cs,container-title=Nullable<T>構造体とヌル許容型)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 値型をベースにしたヌル許容型
+
    int? i = null;
+
    bool? b = null;
+
    Nullable<double> d = null;
+

          
+
    // 参照型をベースにしたヌル許容型を作成することはできない
+
    string? s = null;
+
    // error CS0453: 型 'string' は、ジェネリック型のパラメーター 'T'、またはメソッド 'System.Nullable<T>' として使用するために、Null非許容の値型でなければなりません
+
    Nullable<object> o = null;
+
    // error CS0453: 型 'object' は、ジェネリック型のパラメーター 'T'、またはメソッド 'System.Nullable<T>' として使用するために、Null非許容の値型でなければなりません
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 値型をベースにしたヌル許容型
+
    Dim i As Integer? = Nothing
+
    Dim b As Boolean = Nothing
+
    Dim d As Double = Nothing
+

          
+
    ' 参照型をベースにしたヌル許容型を作成することはできない
+
    Dim s As String? = Nothing
+
    ' error BC33101: 'Nullable' または Null 許容修飾子 '?' と共に使用するためには、型 'String' は 'Structure' に制約されている値型または型引数である必要があります
+
    Dim o As Nullable(Of Object) = Nothing
+
    ' error BC33101: 'Nullable' または Null 許容修飾子 '?' と共に使用するためには、型 'Object' は 'Structure' に制約されている値型または型引数である必要があります
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
また、Nullable構造体を使ってヌル許容型のヌル許容型を構成するといった入れ子にすることもできません。
+

          
+
**ヌル許容型と型情報 [#nullable_type_info]
+
ヌル許容型で&msdn(netfx,member,System.Object.GetType){GetTypeメソッド};を使用して型情報を取得しようとすると、ヌル許容型の元になった型の型情報が返されます。 例えば``int?``では``System.Nullable<System.Int32>``ではなく``System.Int32``が返されます。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型に対するGetType)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // ヌル許容型
+
    int? x = 0;
+

          
+
    Console.WriteLine(x.GetType()); // ベースとなる型(int)の型情報が返される
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' ヌル許容型
+
    Dim x As Integer? = 0
+

          
+
    Console.WriteLine(x.GetType()) ' ベースとなる型(Integer)の型情報が返される
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Int32
+
}}
+

          
+

          
+

          
+
逆に、``typeof``演算子・``GetType``演算子によって型情報を取得する場合、``System.Int32``ではなく``System.Nullable<System.Int32>``が返されます。
+

          
+
#tabpage(codelang=cs,container-title=ヌル許容型の型情報の取得)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // typeof演算子によってint?の型情報を取得する
+
    Console.WriteLine(typeof(int?));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' GetType演算子によってint?の型情報を取得する
+
    Console.WriteLine(GetType(Integer?))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
System.Nullable`1[System.Int32]
+
}}
+

          
+

          
+

          
+
またC#では、ヌル許容型を``is``演算子で比較する場合、元の型が同じであればヌル許容型でもヌル非許容型でも同一の型とみなされます。
+

          
+
#code(cs,ヌル許容型とis演算子での比較){{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // ヌル許容型
+
    int? x = 0;
+

          
+
    // 以下のどちらもtrueとなる
+
    if (x is int?)
+
      Console.WriteLine("x is int?");
+

          
+
    if (x is int)
+
      Console.WriteLine("x is int");
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
x is int?
+
x is int
+
}}
+

          
+
このように、``is``演算子では方がヌル許容型かヌル非許容型かを区別することができません。 ヌル許容型かどうかを調べる方法については後述の[[#check_is_nullable]]で解説します。
+

          
+
**型あるいは値がヌル許容型かどうかを調べる [#check_is_nullable]
+
C#・VBでは、型がヌル許容型かどうかを調べる手段は言語の機能としては用意されていません。 代わりに、&msdn(netfx,member,System.Nullable.GetUnderlyingType){Nullable.GetUnderlyingTypeメソッド};を使って調べることができます。
+

          
+
Nullable.GetUnderlyingTypeメソッドは、ヌル許容型のベースとなる型の型情報(&msdn(netfx,type,System.Type);)を返します(例えば``int?``なら``int``)。 ヌル許容型でない場合、このメソッドは``null``を返すので、これによって型がヌル許容型かそうでないかを判別することができます。
+

          
+
#tabpage(codelang=cs,container-title=Nullable.GetUnderlyingTypeメソッドを使ってベースとなる型の型情報を取得する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    Console.WriteLine("int? : {0}", Nullable.GetUnderlyingType(typeof(int?)));
+
    Console.WriteLine("int : {0}", Nullable.GetUnderlyingType(typeof(int)));
+
    Console.WriteLine("object : {0}", Nullable.GetUnderlyingType(typeof(object)));
+
    Console.WriteLine("string : {0}", Nullable.GetUnderlyingType(typeof(string)));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Console.WriteLine("Integer? : {0}", Nullable.GetUnderlyingType(GetType(Integer?)))
+
    Console.WriteLine("Integer : {0}", Nullable.GetUnderlyingType(GetType(Integer)))
+
    Console.WriteLine("Object : {0}", Nullable.GetUnderlyingType(GetType(Object)))
+
    Console.WriteLine("String : {0}", Nullable.GetUnderlyingType(GetType(String)))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
int? : System.Int32
+
int : 
+
object : 
+
string : 
+
}}
+

          
+

          
+

          
+
[[#nullable_type_info]]でも述べているとおり、ヌル許容型でのGetType()メソッドによる型情報の取得や``is演算子``による比較では、ベースとなっている型情報に対して行われるため、これを用いてヌル許容型かどうかを調べることができません。 値(インスタンス)がヌル許容型かどうかを調べるには、いくつか方法が考えられます。
+

          
+
ひとつは、以下のようなジェネリックメソッドを用意し、型引数Tに対してNullable.GetUnderlyingTypeを呼び出すことでヌル許容型かどうかを判別する方法です。 ただし、この方法では``Object``型に代入されたヌル許容型の値は、ヌル非許容型として判別されます。
+

          
+
#tabpage(codelang=cs,container-title=インスタンスがヌル許容型かどうかを判別する)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  // 引数で与えられた値がヌル許容型かどうかを調べる
+
  static bool IsNullable<T>(T val)
+
  {
+
    // 型引数Tからベースとなる型を取得できるかどうかでヌル許容型かどうかを判別する
+
    return Nullable.GetUnderlyingType(typeof(T)) != null;
+
  }
+

          
+
  public static void Main()
+
  {
+
    int? x = 0;
+
    int y = 0;
+

          
+
    Console.WriteLine("x: {0}", IsNullable(x));
+
    Console.WriteLine("y: {0}", IsNullable(y));
+

          
+
    // この方法ではobject型に代入したヌル許容型を正しく判別できない
+
    object o = x;
+

          
+
    Console.WriteLine("o: {0}", IsNullable(o));
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  ' 引数に指定された値がヌル許容型かどうかを調べる
+
  Function Shared IsNullable(Of T)(ByVal val As T) As Boolean
+
    ' 型引数Tからベースとなる型を取得できるかどうかでヌル許容型かどうかを判別する
+
    Return (Nullable.GetUnderlyingType(GetType(T)) IsNot Nothing)
+
  End Function
+

          
+
  Public Shared Sub Main()
+
    Dim x As Integer? = 0
+
    Dim y As Integer = 0
+

          
+
    Console.WriteLine("x: {0}", IsNullable(x))
+
    Console.WriteLine("y: {0}", IsNullable(y))
+

          
+
    ' この方法ではobject型に代入したヌル許容型を正しく判別できない
+
    Dim o As Object = x
+

          
+
    Console.WriteLine("o: {0}", IsNullable(o))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
x: True
+
y: False
+
o: False
+
}}
+

          
+
この他にも[[c# - How to check if an object is nullable? - Stack Overflow>http://stackoverflow.com/questions/374651/how-to-check-if-an-object-is-nullable]]にて様々な手法が掲載されています。
+

          
+

          
+
**Nullable<T>のデフォルト値
+
``default(T)``や``new``によって作成されるデフォルト状態のNullable<T>(Nullable<T>の規定値)は、HasValueが``false``であり、``null``が設定されている状態と等しくなります。
+

          
+
#tabpage(codelang=cs,container-title=Nullable<T>のデフォルト値)
+
#code{{
+
using System;
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    var x = new Nullable<int>();
+
    var y = default(Nullable<int>);
+

          
+
    Console.WriteLine(x.HasValue);
+
    Console.WriteLine(y.HasValue);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Dim x As New Nullable(Of Integer)()
+
    Dim y As Nullable(Of Integer) = Nothing
+
    ' Dim z As Integer = Nothing (Integerのデフォルト値の取得)
+

          
+
    Console.WriteLine(x.HasValue)
+
    Console.WriteLine(y.HasValue)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
False
+
False
+
}}
+

          
+
#relevantdocs
+

          
+
-[[programming/netfx/basic_types/0_characteristics#DefaultValue]]
+

          
+
#relevantdocs-end
+

          
+

          
+

          
+
*ヌル非許容の参照型
+
値型``ValType``におけるヌル許容型``ValType?``に対して、参照型``RefType``をヌル非許容にした型``RefType!``のようなものは現時点では用意されておらず、作成することはできません。 ヌル非許容型を使用したい場合は、``struct``によって値型とするか、''契約プログラミング''の手法を用いるなど、他の手段によって``null``を非許容とする制約を施すほかありません。
+

          
+
#relevantdocs(参考)
+

          
+
-[[C#のNull非許容型の提案:http://www.infoq.com/jp/news/2012/10/Null-CSharp]]
+
-[[Proposal for C# Non-Nullable Reference Types:https://gist.github.com/olmobrutall/31d2abafe0b21b017d56]]
+

          
+
#relevantdocs-end
+

          
+

          
+

          
+

          
+

          
+

          
+

          
+

          
+

          
+