次の方法で共有


null 許容値型 (C# リファレンス)

"null 許容値型" T? は、基になる値型T のすべての値と、追加の null 値を表します。 たとえば、bool? 変数には、truefalsenull の 3 つの値のいずれかを割り当てることができます。 基になる値型 T null 許容値型自体にすることはできません。

C# 言語リファレンスには、C# 言語の最新リリース バージョンが記載されています。 また、今後の言語リリースのパブリック プレビューの機能に関する初期ドキュメントも含まれています。

このドキュメントでは、言語の最後の 3 つのバージョンまたは現在のパブリック プレビューで最初に導入された機能を特定します。

ヒント

C# で機能が初めて導入された時期を確認するには、 C# 言語バージョン履歴に関する記事を参照してください。

null 許容値型は、ジェネリック System.Nullable<T> 構造体のインスタンスです。 T または Nullable<T> の代替可能な形式のいずれかで基になる型 T? を持つ null 許容値型を参照できます。

通常、基になる値型の未定義の値を表す必要がある場合は、null 許容値型を使用します。 たとえば、ブール型 (bool) 変数で可能なのは、true または false のいずれかです。 ただし、一部のアプリケーションでは、変数の値が未定義または存在しない場合があります。 たとえば、データベース フィールドに true または falseを含めたり、値をまったく含めなかったりする場合があります。つまり、 NULL。 このシナリオでは、bool? 型を使用できます。

宣言と代入

値型は対応する null 許容値型に暗黙的に変換できるため、基になる値型の場合と同様に、null 許容値型の変数に値を割り当てることができます。 null 値を代入することもできます。 次に例を示します。

double? pi = 3.14;
char? letter = 'a';

int m2 = 10;
int? m = m2;

bool? flag = null;

// An array of a nullable value type:
int?[] arr = new int?[10];

null 許容値型の既定値は、 nullを表します。 Nullable<T>.HasValue プロパティがfalseを返すインスタンスです。

null 許容値型のインスタンスの検査

nullの null 許容値型のインスタンスを確認し、基になる型の値を取得するには、型パターンで is 演算子を使用します。

int? a = 42;
if (a is int valueOfA)
{
    Console.WriteLine($"a is {valueOfA}");
}
else
{
    Console.WriteLine("a does not have a value");
}
// Output:
// a is 42

次の読み取り専用プロパティを常に使用して、null 許容値型変数の値を確認して取得できます。

次の例では、 HasValue プロパティを使用して、変数に値が含まれているかどうかを確認してから表示します。

int? b = 10;
if (b.HasValue)
{
    Console.WriteLine($"b is {b.Value}");
}
else
{
    Console.WriteLine("b does not have a value");
}
// Output:
// b is 10

次の例に示すように、null プロパティを使用する代わりに、null 許容値型の変数を HasValue と比較することもできます。

int? c = 7;
if (c != null)
{
    Console.WriteLine($"c is {c.Value}");
}
else
{
    Console.WriteLine("c does not have a value");
}
// Output:
// c is 7

null 許容値型から基になる型への変換

null 許容値型の値を null 非許容値型変数に割り当てる場合は、 nullの代わりに割り当てる値を指定する必要があります。 これを行うには、 null 合体演算子 ?? を使用します。 同じ目的で Nullable<T>.GetValueOrDefault(T) メソッドを使用することもできます。

int? a = 28;
int b = a ?? -1;
Console.WriteLine($"b is {b}");  // output: b is 28

int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}");  // output: d is -1

の代わりに基になる値の型のnull値を使用する場合は、Nullable<T>.GetValueOrDefault() メソッドを使用します。

次の例に示すように、null 許容値型を null 非許容型に明示的にキャストすることもできます。

int? n = null;

//int m1 = n;    // Doesn't compile
int n2 = (int)n; // Compiles, but throws an exception if n is null

実行時に null 許容値型の値が null の場合は、明示的なキャストによって InvalidOperationException がスローされます。

null 非許容値型 T は、対応する null 許容値型 T? に暗黙的に変換されます。

リフト演算子

null 許容値型 T? は、定義済みの単項演算子と二項 演算子 、または値型 T がサポートするオーバーロードされた演算子をサポートします。 これらの演算子 (リフト演算子とも呼ばれます) は、一方または両方のオペランドがnull場合にnullを返します。 それ以外の場合、演算子はオペランドの包含値を使用して結果を計算します。 次に例を示します。

int? a = 10;
int? b = null;
int? c = 10;

a++;        // a is 11
a = a * c;  // a is 110
a = a + b;  // a is null

注意

bool? 型の場合、定義済みの & および | 演算子は、このセクションで説明されている規則に従わないことに注意してください。オペランドの 1 つが null の場合も、演算子の評価の結果は null 以外である可能性があります。 詳細については、「Boolean logical operators (ブール論理演算子)」記事の「Nullable Boolean logical operators (null 許容論理演算子)」セクションを参照してください。

比較演算子<><=、および>=の場合、一方または両方のオペランドがnull場合、結果はfalse。 それ以外の場合は、オペランドの包含値が比較されます。 特定の比較 (たとえば、 <=) が falseを返すので、逆の比較 (>) は trueを返します。 次の例は、10 が

  • null 以上ではなく
  • null 未満でもないことを示します
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False

int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True

等値演算子の場合==両方のオペランドがnull場合、結果はtrueされます。 オペランドの 1 つだけが null場合、結果は false。 それ以外の場合は、オペランドの包含値が比較されます。

不等値演算子の場合!=両方のオペランドがnull場合、結果はfalse。 オペランドの 1 つだけが null場合、結果は true。 それ以外の場合は、オペランドの包含値が比較されます。

2 つの値型の間に ユーザー定義変換 が存在する場合は、対応する null 許容値型間で同じ変換を使用することもできます。

ボックス化とボックス化解除

null 許容値型のインスタンスをT?ボックス化すると、次の規則が適用されます。

  • HasValuefalseを返す場合、ボックス化操作は null 参照を返します。
  • HasValuetrueを返す場合、ボックス化操作では、Nullable<T>のインスタンスではなく、基になる値型の対応する値Tボックス化されます。

次の例に示すように、値型 T のボックス化された値を、対応する null 許容値型 T? にボックス化解除できます。

int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");

object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
    Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41

方法: null 許容値型を識別する

次の例は、System.Type インスタンスが構築された null 許容値型 (つまり、指定された型パラメーター System.Nullable<T> を使用する T 型) を表すかどうかを判断する方法を示しています。

Console.WriteLine($"int? is {(IsNullable(typeof(int?)) ? "nullable" : "non nullable")} value type");
Console.WriteLine($"int is {(IsNullable(typeof(int)) ? "nullable" : "non-nullable")} value type");

bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;

// Output:
// int? is nullable value type
// int is non-nullable value type

例で示されているとおり、 インスタンスの作成には、System.Type 演算子を使用します。

インスタンスが null 許容値型であるかどうかを判断する場合は、 Object.GetType メソッドを使用して、上記のコードを使用してテストする Type インスタンスを取得しないでください。 null 許容値型のインスタンスで Object.GetType メソッドを呼び出した場合、そのインスタンスは Objectされます。 null 許容値型の null 以外のインスタンスをボックス化することは、基になる型の値をボックス化することと同じであるため、 GetType は null 許容値型の基になる型を表す Type インスタンスを返します。

int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32

また、インスタンスが null 許容値型であるかどうかを判断するために、is 演算子を使用しないでください。 次の例に示すように、 is 演算子を使用して、null 許容値型インスタンスとその基になる型インスタンスの型を区別することはできません。

int? a = 14;
if (a is int)
{
    Console.WriteLine("int? instance is compatible with int");
}

int b = 17;
if (b is int?)
{
    Console.WriteLine("int instance is compatible with int?");
}
// Output:
// int? instance is compatible with int
// int instance is compatible with int?

代わりに、最初の例の Nullable.GetUnderlyingType メソッドと typeof 演算子を使用して、インスタンスが null 許容値型であるかどうかを確認します。

注意

このセクションで説明するメソッドは、 null 許容参照型には適用されません。

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

関連項目