できない.dev

C# で「CS8618: null 非許容のプロパティ」の警告が消せない

CS8618 は、null 許容参照型を有効にしたプロジェクトで参照型のメンバーがコンストラクター終了時に null のままになりうるときに出る。
値が必ず入るなら required かコンストラクター引数、入らないなら型を null 許容にするのが筋の通し方である。

公開:

要約

CS8618 は「null 非許容のメンバーが、コンストラクターを抜けた時点で null のままになりうる」という警告です。

null 許容参照型(<Nullable>enable</Nullable>)を有効にすると、string は「null が入らない型」という約束になります。
コンパイラーはその約束をコンストラクターの出口で検査するため、代入していないプロパティは約束違反として報告されます。

警告を消すこと自体が目的ではありません。
そのメンバーは本当に必ず値が入るのか、それとも入らないことがあるのかを決めれば、書き方は自動的に決まります。

よくある原因

  1. コンストラクターで代入していない参照型のプロパティがある。
    もっとも多いパターンです。
  2. EF Core や System.Text.Json が実行時に値を流し込むモデルを、素の自動プロパティで宣言している。
    コンパイラーはフレームワークの都合を知らないので警告します。
  3. 初期化処理を別メソッドに切り出している。
    コンストラクターの出口では未代入なので、実行時に問題が無くても警告は出ます。
  4. = 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 を置いて対象外にする方法があります。
ただしこれは移行期間の措置で、恒久的な解にはしないでください。

この記事は役立ちましたか?