Start Debugging

C# 14 の null 条件代入: ?. と ?[] を左辺で使う

C# 14 は null 条件演算子を代入の左辺でも動作するように拡張し、プロパティやインデクサーを設定する際の冗長な null チェックを排除します。

C# 14 は小さくとも影響力のある変更をもたらします。null 条件演算子 ?.?[] が代入の左辺でも使えるようになりました。これにより、プロパティ代入を null チェックでラップする一般的なパターンが不要になります。

置き換えられる冗長なパターン

C# 14 以前は、オブジェクトが null でない場合にのみプロパティに代入するには、明示的なチェックが必要でした。

if (customer is not null)
{
    customer.LastOrderDate = DateTime.UtcNow;
}

if (settings is not null)
{
    settings["theme"] = "dark";
}

深くネストされたオブジェクトでは、これがさらに悪化していました。

if (order?.Customer?.Address is not null)
{
    order.Customer.Address.IsVerified = true;
}

C# 14 の null 条件代入

C# 14 では、同じロジックをより簡潔に書くことができます。

customer?.LastOrderDate = DateTime.UtcNow;

settings?["theme"] = "dark";

order?.Customer?.Address?.IsVerified = true;

代入は左辺が null 以外の参照に評価された場合にのみ実行されます。対象が null の場合、右辺は評価されません。

動作の仕組み

P?.A = B は次と同等です。

if (P is not null)
{
    P.A = B;
}

ただし重要な違いがあります。P は一度しか評価されません。これは P がメソッド呼び出しであったり副作用がある場合に重要です。

複合代入演算子

null 条件代入は +=-=*= などの複合演算子でも動作します。

inventory?.StockLevel += restockAmount;

counter?.Value -= 1;

account?.Balance *= interestRate;

これらはいずれも左辺を一度評価し、対象が null でない場合にのみ操作を適用します。

インクリメントとデクリメントは許可されない

ひとつの制限として、++-- 演算子は null 条件代入では使えません。次のコードはコンパイルできません。

// Error: ++ and -- not allowed
counter?.Value++;

代わりに複合代入を使用します。

counter?.Value += 1;

実用例: イベントハンドラー

一般的なユースケースは、イベントハンドラーを条件付きで設定することです。

public void Initialize(Button? submitButton, Button? cancelButton)
{
    submitButton?.Click += OnSubmit;
    cancelButton?.Click += OnCancel;
}

null 条件代入がなければ、ボタンごとに別々の null チェックが必要になります。

インデクサーとの連鎖

?[] 演算子はインデクサー代入でも同じように動作します。

Dictionary<string, string>? headers = GetHeaders();

headers?["Authorization"] = $"Bearer {token}";
headers?["Content-Type"] = "application/json";

headers が null の場合、いずれの代入も実行されず、例外もスローされません。

使いどころ

null 条件代入は次のような場面で最も効果的です。

この機能は .NET 10 と C# 14 で利用可能です。プロジェクトファイルで <LangVersion>14</LangVersion> を設定して有効にしてください。

完全な仕様については、Microsoft Learn の Null 条件代入 を参照してください。

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< 戻る