AIはC#コードを人より速く書きます。一方で、直すのに追いつかないことも珍しくありません。

InfoWorldが2026年7月2日に公開した解説では、GitHub CopilotやClaude Code、Cursor、ChatGPTを使う.NET開発者向けに、生成コードの品質・安全・保守性を守る実践を整理しています(参考)。

この記事では、その要点を日本の開発現場向けに再構成し、すぐ試せるプロンプト例とレビュー観点までまとめます。

この記事でわかること

  • AI生成C#が本番で失敗しやすい7つの理由
  • Copilotに渡すべきプロンプトの書き方と具体例
  • 非同期ロガー生成で見つかった3つの典型的な欠陥
  • 本番投入前に確認するレビューチェックリスト

生成は速いが、品質はプロンプトと文脈次第

GitHub CopilotはVisual StudioやVS Codeに統合され、コメントから補完やチャット経由の生成ができます。Claude Codeはターミナル起点のエージェントとして、リポジトリ全体を読みながら複数ファイルの変更やテスト実行まで任せられるツールです。CursorはVS Code派生のIDEで、エージェント的なマルチファイル編集に強みがあります。

いずれも「書く速度」は人間を上回ります。ただし、同じ指示でも出力は毎回ぶれます。ロジックエラー、セキュリティ上の穴、社内規約との不一致、アーキテクチャとの不整合、過剰な抽象化、ハッピーパスだけのエラー処理など、本番投入前に潰すべき問題が混ざります。オープンソース由来の学習データに弱い検証やハードコードされた秘密情報が含まれるリスクも、無視できません。

課題は「AIを置き換え」ではなく「レビュー前提の同僚」として使うこと

多くのチームがつまずくのは、生成速度に品質チェックが追いつかない点です。AIはジュニアの同僚のように扱い、生成→テスト→監査→リファクタのサイクルを回すのが基本です。速度を優先して理解を省略すると、本番デプロイ後に障害へつながります。

効く対策は4つに集約されます。プロンプトを具体的に書く。アーキテクチャ文書やコーディング規約、関連ファイルを先に渡して文脈を厚くする。生成と同時にテスト条件を書く。完了の定義(スタック、境界、期待する振る舞い)を明示する。スクリーンショットを添えると、UIや画面仕様の解釈も安定しやすくなります。

GitHub CopilotでDTOを書かせる——曖昧な指示の代償

DTO(Data Transfer Object)は、プレゼンテーション層からビジネス層へデータを運ぶための入れ物です。C#では不変のrecord型がパフォーマンスとスレッド安全性の面で有利な場面が多く、変更を防ぎテストもしやすくなります。

InfoWorldの検証では、次の曖昧なプロンプトをCopilot Chatに渡したところ、可変なclassが生成されました。

Generate code to create a Product DTO having fields Id, Name, and Price

出力はpublic class Productで、コンストラクタ付きの可変プロパティでした。DTOの目的(不変でデータを運ぶ)が指示に含まれていないため、動くコードではあるものの、意図から外れています。

プロンプトを次のように具体化すると、結果は1行の不変レコードに変わります。

Create an immutable Product DTO using C# that uses the record type, having fields Id, Name, and Price.

public sealed record ProductDto(int Id, string Name, decimal Price);

「DTO」「不変」「record」と要件を言語化するだけで、保守しやすい形に寄せられます。Claude CodeやCursorでも同じ原則が効きます。型やパターン名をプロンプトに入れるほど、.NETらしい出力に近づきます。

.NET 10向け非同期ロガー生成で露わになった3つの欠陥

同じ解説では、Visual Studio上のCopilotに対し、.NET 10とC# 14を前提とした非同期ロガー作成を依頼しています。要件は、ファイルまたはSQLiteへの非同期保存、ターゲットごとにFileLoggerDbLoggerを分離、エラー処理の網羅です。CopilotはAsyncLoggerクラスライブラリとコンソールアプリを生成し、System.Threading.ChannelLogEntryを書き込む構成を提案しました。

ここからが本番投入前のレビューです。生成物は動いて見えても、負荷下では別物になります。

Unboundedチャネルはバースト流量でメモリを食う

生成コードはChannel.CreateUnboundedを使っていました。無制限キューは、秒間1万リクエスト超のようなバースト時にメモリ消費が急増し、GC圧迫やプロセスクラッシュにつながります。CreateBoundedで容量上限(例: 10,000)とFullModeDropWriteWait)を明示する方が安全です。

fire-and-forgetのTryWriteは失敗を見逃す

LogAsync内の_channel.Writer.TryWrite(entry)は、チャネルが閉じた場合のリトライやフォールバックがありません。WaitToWriteAsyncで書き込み可否を待ち、失敗時は別ファイルへ退避するフォールバックパスを用意するのが実務的です。

コンストラクタでのsync-over-asyncはデッドロックの温床

コンストラクタ内の_target.InitializeAsync(_cts.Token).GetAwaiter().GetResult()は、C#では避けるべきアンチパターンです。コンストラクタはasyncにできないため、ブロッキング呼び出しがスレッド飢餓やデッドロックを招きます。初期化はpublic async Task InitializeAsync()のようにコンストラクタ外へ移します。

Claude Codeを使うときの位置づけ

https://docs.anthropic.com/en/docs/claude-code/overview

Claude CodeはIDE補完型ではなく、シェル上でリポジトリ全体を読み、テスト実行やgit操作まで含めて自律的に作業するエージェントです。大規模リファクタや横断的な変更に向きます。一方、1行単位の補完やVisual Studioネイティブな体験はCopilotの方が自然です。多くのチームは、日常のインライン補完をCopilot、リポジトリ横断の大きな変更をClaude Code、という使い分けを検討しています(参考)。

どちらを選んでも、上記3欠陥のような「動くが危ない」コードは出ます。ターミナルで完結するからこそ、生成後のテストと静的解析を省略しないことが重要です。

本番投入前チェックリスト

InfoWorldが提示する確認項目は、C#/.NET文脈でそのまま使えます。

  • 要件をすべて満たしているか
  • SQLインジェクションやXSSなどの脆弱性がないか
  • C#のコーディング規約と命名規則に沿っているか
  • N+1クエリなど非効率なデータアクセスがないか
  • 非同期処理、入力検証、設定、ロギングが適切か
  • テスト可能な抽象化になっているか
  • 期待するコードカバレッジを満たすテストがあるか

ボイラープレート生成や調査の加速にAIを使い、設計判断と最終責任は人間が持つ——この線引きが、速さと品質を両立する鍵です。アーキテクチャ案の生成も参考程度に留め、採用範囲は自分で決めてください。AIは交代要員ではなく、反復レビューを前提にした共同作業者として扱うのが、2026年時点の現実的な使い方です。