はじめに
ローカルの Visual Studio (VS) で整形しても、CI パイプラインや dotnet format コマンドを実行すると意図しない修正(例:EF Core の DbSet への ? 付与)が走る現象があります。
動作確認環境
- .NET 10
- Visual Studio 2026
1. 挙動が食い違う根本原因
VS の「ドキュメントのフォーマット (Ctrl+K, D)」と dotnet format コマンドでは、対象とする修正レイヤーが異なります。
| 修正レイヤー | 内容 | VS デフォルト (Ctrl+K, D) | dotnet format |
|---|---|---|---|
| Whitespace | インデント、改行、空白 | ✅ | ✅ |
| Code Style |
this. の省略、変数宣言スタイル |
❌ | ✅ |
| Analyzers | Null 許容の警告 (CS8618) 等の自動修正 | ❌ | ✅ |
VS はデフォルトで「見た目」のみを整えますが、dotnet format は Analyzer(静的解析)に基づいたコードの意味的な修正まで踏み込むため、乖離が発生します。
2. EF Core DbSet プロパティの「勝手に修正」問題
現象
// 修正前
public DbSet<Todo> Todos { get; set; }
// dotnet format 実行後
public DbSet<Todo>? Todos { get; set; }
これは、非 nullable プロパティがコンストラクタで初期化されていない(CS8618)ことに対する、Analyzer の「Null 許容にすれば警告が消える」という機械的な判断によるものです。
推奨される実装(.NET 10 標準)
EF Core プロパティに対しては、? を付けるのではなく、「フレームワークが初期化することを明示する」 のが正解です。
public DbSet<Todo> Todos { get; set; } = default!;
3. CI パイプラインにおける推奨構成
CI で whitespace や style のみに限定するのは、コード品質の低下を招くため推奨されません。「フルチェックを実行しつつ、不要なルールを .editorconfig で除外する」 のがベストプラクティスです。
🛠️ パイプラインでの実行コマンド
dotnet format --verify-no-changes --severity info
-
--verify-no-changes: 修正は行わず、ルール違反があれば終了コード1を返し、CI を落とします。 -
--severity info:infoレベル以上のルールをチェック対象にします。
⚙️ .editorconfig による制御
勝手な修正を抑制したい場合は、コマンド引数を変えるのではなく、設定ファイルでルールの重要度を調整します。
[*.cs]
# 基本は Analyzer まで含める
dotnet_analyzer_diagnostic.category-Style.severity = suggestion
dotnet_analyzer_diagnostic.category-CodeQuality.severity = warning
# 特定のルール (CS8618: 未初期化プロパティ) の自動修正を抑制
# severity を suggestion 以下に設定
dotnet_diagnostic.CS8618.severity = suggestion
4. Visual Studio 側の同期設定
開発者がプッシュする前に差分に気づけるよう、VS 側で「保存時の自動クリーンアップ」を有効化します。
- [ツール] > [オプション] > [テキスト エディター] > [Code Cleanup]
- [プロファイルの保存]で[コードのクリーンアップ] に対象のプロファイルを設定
さいごに
-
実装ルール: EF Core の
DbSetは= default!;を付与し、不必要な?の自動挿入を物理的に防ぐ。 -
CI ルール:
dotnet format --verify-no-changesを実行し、全レイヤーの整合性を担保する。 -
管理ルール: ルールの例外(除外設定)は、コマンド引数ではなく
.editorconfigでコードとして管理する。
これにより、ローカル環境と CI パイプラインの間で「構成のドリフト」が発生しない、堅牢な開発ワークフローが実現します。
参考