今回はC# 14で追加された「null条件付きの代入」を扱います。
null条件付き(?を付ける書き方)でnullかどうかをチェックしてから処理する、という書き方自体はこれまでのバージョンでも可能でした。例えばProductクラスが次のように定義されているとします。
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
このProduct型の変数pがnullかもしれない状況で、次のように書くことは以前のバージョンでも可能でした。
p?.ProductId == 1
C# 13以前:読み込みはできるが書き込みはできない
以下はVisual Studio 2022(C# 13)で確認している内容です。まずタイトルスライドで今回のテーマを確認します。
図1 タイトルスライド「【C#14】Null条件付き代入」
Productクラスを定義し、ProductIdプロパティを用意します。
図2 Productクラスの定義(ProductIdプロパティ)
Product型の変数pをnullで初期化し、if文でp?.ProductId == 1のように読み込みを行う書き方は、C# 13以前でも問題なく書けます。pがnullであれば1と等しくないと判定され、nullでなければProductIdが1かどうかがチェックされる、という流れです。
図3 if (p?.ProductId == 1) と書いた状態(読み込みは可能)
一方で、同じ?を使ってp?.ProductId = 999;のように代入(書き込み)しようとすると、C# 13以前ではエラーになります。pがnullだった場合にnullへ999を代入することになってしまい、意味が通らなくなるためです。このように、これまでは?を付けた変数への代入という書き方自体ができませんでした。
図4 p?.ProductId = 999; はCS0131エラーになる(代入式の左辺には変数、プロパティ、またはインデクサーを指定してください)
C# 14:null条件付き代入が可能に
続いてVisual Studio 2026(C# 14)で同じコードを書いてみます。新規にWindowsフォームアプリのプロジェクトを作成します。
図5 Visual Studio 2026で新規作成したプロジェクト(WinFormsApp2026)
先ほどと同じProductクラスとp?.ProductId == 1の判定に加えて、p?.ProductId = 999;という代入も書いてみます。C# 14ではどちらもエラーにならず、書けるようになっています。
Product p = null;
if (p?.ProductId == 1)
{
}
p?.ProductId = 999;
実際に動かして確認します。pはnullの状態なので、p?.ProductId = 999;を通過してもエラーにならず、pはnullのままであることが確認できます。ブレークポイントで停止した状態でp?.ProductIdにカーソルを合わせると、値がnullであることがわかります。
図6 ブレークポイントでp?.ProductId = 999; の直前を確認(p?.ProductId は null)
図7 デバッグ実行で行を通過(0エラーで実行できている)
内部的な動き
null条件付き代入p?.ProductId = 999;は、内部的には次のコードと同じ意味になります。pのnullチェックを行ってから、nullでなければ代入を行う、という処理です。
図8 p?.ProductId = 999; と、それと同じ意味を持つ if (p != null) { p.ProductId = 999; }
p?.ProductId = 999;
// 上記は次のコードと同じ意味
if (p != null)
{
p.ProductId = 999;
}
これまでは「?を付けた変数への代入」という書き方ができませんでしたが、C# 14以降ではこのnull条件付きの代入が可能になりました。
Udemyでの動画版はこちらからご覧いただけます
00_はじめに
01_VisualStudio2026をインストールしてください
A01_fieldキーワード
B01_extensionブロックとは
B02_拡張メソッドとは
B03_extensionブロック
B04_型パラメータありの拡張メソッド
B05_型パラメータありのextensionブロックの書き方
B06_拡張プロパティ
B07_拡張静的プロパティ&メソッド
B08_拡張演算子
C01_partialコンストラクター
C02_幽霊コードを定義パーツで契約による実装をするという考え方
C03_partialイベント
D01_Null条件付き代入
E01_複合代入演算子のオーバーロード
F01_明示的な型を指定せずにラムダパラメータでパラメータ修飾子を使用する
G01_nameofはバインドされていないジェネリック型をサポートします
H01_SpanTおよびReadOnlySpanTのより暗黙的な変換
Udemyでの動画版はこちらからご覧いただけます