C# で「CS8618: null 非許容のプロパティ」の警告が消せない
CS8618 は、null 許容参照型を有効にしたプロジェクトで参照型のメンバーがコンストラクター終了時に null のままになりうるときに出る。
値が必ず入るなら required かコンストラクター引数、入らないなら型を null 許容にするのが筋の通し方である。
公開:
要約
CS8618 は「null 非許容のメンバーが、コンストラクターを抜けた時点で null のままになりうる」という警告です。
null 許容参照型(<Nullable>enable</Nullable>)を有効にすると、string は「null が入らない型」という約束になります。
コンパイラーはその約束をコンストラクターの出口で検査するため、代入していないプロパティは約束違反として報告されます。
警告を消すこと自体が目的ではありません。
そのメンバーは本当に必ず値が入るのか、それとも入らないことがあるのかを決めれば、書き方は自動的に決まります。
よくある原因
- コンストラクターで代入していない参照型のプロパティがある。
もっとも多いパターンです。 - EF Core や
System.Text.Jsonが実行時に値を流し込むモデルを、素の自動プロパティで宣言している。
コンパイラーはフレームワークの都合を知らないので警告します。 - 初期化処理を別メソッドに切り出している。
コンストラクターの出口では未代入なので、実行時に問題が無くても警告は出ます。 = null!を全メンバーに機械的に付けている。
警告は消えますが、本当に null が入りうるメンバーのNullReferenceExceptionを実行時まで先送りしているだけです。
解決策
1. コンストラクターで代入する
必須の値であることをコンストラクターのシグネチャで表明するのが、もっとも意図の伝わる形です。
public class User
{
public string Name { get; }
public string Email { get; }
public User(string name, string email)
{
Name = name;
Email = email;
}
}2. C# 11 以降なら required を付ける
オブジェクト初期化子で組み立てたい場合は、required を付けると設定漏れがコンパイルエラーになります。
コンストラクターを増やさずに「必須」を表現できます。
public class User
{
public required string Name { get; set; }
public required string Email { get; set; }
}
// Name を書かないとコンパイルエラーになる
var user = new User { Name = "sasaki", Email = "sasaki@example.com" };required は C# 11(.NET 7)以降の機能です。LangVersion が古いプロジェクトでは使えません。
3. フレームワークが入れる値は null! で免除する
EF Core のナビゲーションプロパティのように、実行時に必ず値が入るのにコンパイラーには証明できないものだけ、null! で明示的に免除します。
public class Order
{
public int UserId { get; set; }
// EF Core が Include 時に設定する。呼び出し側では非 null として扱ってよい
public User User { get; set; } = null!;
}null! は「私が保証する」という宣言です。
保証できないメンバーには使わないでください。
4. null がありうるなら型を null 許容にする
値が入らないことがあるなら、それは設計上 string? です。
型を正直にすれば警告は消え、使う側は null チェックを促されます。
public class Profile
{
public string? Nickname { get; set; }
}
// 使う側
var length = profile.Nickname?.Length ?? 0;5. 段階的に導入したい場合
既存プロジェクトを一度に直せないときは、プロジェクト単位で enable にする代わりに警告レベルだけを上げる、あるいはファイル先頭に #nullable disable を置いて対象外にする方法があります。
ただしこれは移行期間の措置で、恒久的な解にはしないでください。