できない.dev

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

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

公開: 更新:

症状できない · exit 1
dotnet build
…
/tmp/tmp.46dL4cUzJL/app/Program.cs(1,16): error CS9035: Required member 'User.Name' must be set in the object initializer or attribute constructor. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
Build FAILED.
解決後できた · exit 0
dotnet build
…
    0 Warning(s)
    0 Error(s)
Time Elapsed 00:00:00.67

2026-10-03 に mcr.microsoft.com/dotnet/sdk:8.0(Git 2.39.5) で実際に打って取った出力。検証環境の詳細

要約

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

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

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

実行例

<Nullable>enable</Nullable> の入った net8.0 のプロジェクトで、参照型の Name と Email を初期化せずにビルドすると warning CS8618 が 2 件出るが、ビルド自体は成功した。required を付けて Name を設定しない初期化子を書くと error CS9035 で Build FAILED になり、設定漏れを直して null がありうるメンバーを string? に変えたあとは警告 0・エラー 0 でビルドが通り、dotnet run は sasaki 0 を出力している。

$ grep Nullable app.csproj
    <Nullable>enable</Nullable>
$ dotnet build
  Determining projects to restore...
  All projects are up-to-date for restore.
/tmp/tmp.46dL4cUzJL/app/User.cs(3,19): warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
/tmp/tmp.46dL4cUzJL/app/User.cs(4,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
  app -> /tmp/tmp.46dL4cUzJL/app/bin/Debug/net8.0/app.dll
 
Build succeeded.
 
/tmp/tmp.46dL4cUzJL/app/User.cs(3,19): warning CS8618: Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
/tmp/tmp.46dL4cUzJL/app/User.cs(4,19): warning CS8618: Non-nullable property 'Email' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
    2 Warning(s)
    0 Error(s)
 
Time Elapsed 00:00:01.89
$ echo $?
0
$ dotnet build
  Determining projects to restore...
  All projects are up-to-date for restore.
/tmp/tmp.46dL4cUzJL/app/Program.cs(1,16): error CS9035: Required member 'User.Name' must be set in the object initializer or attribute constructor. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
 
Build FAILED.
 
/tmp/tmp.46dL4cUzJL/app/Program.cs(1,16): error CS9035: Required member 'User.Name' must be set in the object initializer or attribute constructor. [/tmp/tmp.46dL4cUzJL/app/app.csproj]
    0 Warning(s)
    1 Error(s)
 
Time Elapsed 00:00:00.64
$ echo $?
1
$ dotnet build
  Determining projects to restore...
  All projects are up-to-date for restore.
  app -> /tmp/tmp.46dL4cUzJL/app/bin/Debug/net8.0/app.dll
 
Build succeeded.
    0 Warning(s)
    0 Error(s)
 
Time Elapsed 00:00:00.67
$ echo $?
0
$ dotnet run
sasaki 0

— 2026-10-03 時点の出力

検証環境Git 2.39.5 / 2026-10-03 検証
検証日
実行環境
mcr.microsoft.com/dotnet/sdk:8.0 Debian GNU/Linux 12 (bookworm)
バージョン
  • Git 2.39.5

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

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 を置いて対象外にする方法があります。
ただしこれは移行期間の措置で、恒久的な解にはしないでください。

よくある原因

  1. コンストラクターで代入していない参照型のプロパティがある。
    もっとも多いパターンです。
  2. EF Core や System.Text.Json が実行時に値を流し込むモデルを、素の自動プロパティで宣言している。
    コンパイラーはフレームワークの都合を知らないので警告します。
  3. 初期化処理を別メソッドに切り出している。
    コンストラクターの出口では未代入なので、実行時に問題が無くても警告は出ます。
  4. = null! を全メンバーに機械的に付けている。
    警告は消えますが、本当に null が入りうるメンバーの NullReferenceException を実行時まで先送りしているだけです。

この手順で直った?