C#では、nullリテラルは値が存在しないことを表すために使います。_null許容_型とは、nullの値を受け入れる型のことです。
C# 8.0より前は、参照型は常にnull許容でしたが、値型はそうではありませんでした。値型は、末尾に疑問符(?)を付けることでnull許容にできます。
string nullableReferenceType = "hello";
nullableReferenceType = null; // Valid as type is nullable
int nonNullableValueType = 5;
nonNullableValueType = null; // Compile error as type is not nullable
int? nullableValueType = 5; // Define nullable value type
nullableValueType = null; // Valid as type is nullable
nullの変数のメンバーにアクセスしてもコンパイルエラーにはなりませんが、実行時にNullReferenceExceptionがスローされます。
string sentence = null;
// Throws NullReferenceException at runtime
sentence.Length;
こうしたよくある間違いに対処するために、C# 8では、参照型をデフォルトでnull非許容にする機能にオプトインできます。
string nonNullableReferenceType = "book";
nonNullableReferenceType = null; // Compile warning (no error!)
string? nullableReferenceType = "movie";
nullableReferenceType = null; // Valid as type is nullable
null許容の値を安全に扱うには、使う前にnullかどうかを確認します。
string NormalizedName(string? name)
{
if (name == null)
{
return "UNKNOWN";
}
// Value is not null at this point, so no compile warning
// and no runtime NullReferenceException being thrown
return name.ToUpper();
}
NormalizedName(null); // => "UNKNOWN"
NormalizedName("Elisabeth"); // => "ELISABETH"
??演算子を使うと、値がnullのときにデフォルト値を返すことができます。
string? name1 = "John";
name1 ?? "Paul"; // => "John"
string? name2 = null;
name2 ?? "George"; // => "George"
?.演算子を使うと、nullの可能性がある値のメンバーを安全に呼び出せます。
string? fruit = "apple";
fruit?.Length; // => 5
string? vegetable = null;
vegetable?.Length; // => null
この演習では、工場の従業員向けの名札を出力するコードを書きます。
従業員にはID、名前、部署名があります。従業員の名札のラベルは、次の形式です:"[id] - name - DEPARTMENT"。従業員の名札のラベルを返すように、(static)Badge.Print()メソッドを実装しましょう。
Badge.Print(734, "Ernest Johnny Payne", "Strategic Communication");
// => "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION"
なお、ラベルでは部署名を大文字にします。
コンピューターシステムの不具合により、新しい従業員が工場で働き始めるとき、まだIDを持っていないことがあります。名札は必須なので、その場合はIDの接頭辞がない一時的な名札が渡されます。まだIDを持っていない新しい従業員に対応できるように、(static)Badge.Print()メソッドを変更しましょう。
Badge.Print(id: null, "Jane Johnson", "Procurement");
// => "Jane Johnson - PROCUREMENT"
工場のオーナーも、いつでも名札を着けなければなりません。ただし、オーナーには部署がありません。この場合は、ラベルに部署名の代わりに"OWNER"と出力します。オーナーのラベルを出力するように、(static)Badge.Print()メソッドを変更しましょう。
Badge.Print(254, "Charlotte Hale", department: null);
// => "[254] - Charlotte Hale - OWNER"
オーナーが新しい従業員でもある場合があることに注意しましょう。
Badge.Print(id: null, "Charlotte Hale", department: null);
// => "Charlotte Hale - OWNER"