dotnet-aot-compat
ILトリム/AOTアナライザーの警告(IL2026、IL2070、IL2067、IL2072、IL3050など)を体系的に解消し、.NETプロジェクトをNative AOTおよびトリミングに対応させるスキルです。`DynamicallyAccessedMembers`アノテーションの追加や`IsAotCompatible`の有効化など、AOT互換性確保に必要な修正を純粋なナレッジベースで提案します。ネイティブAOTバイナリのパブリッシュやバイナリサイズの最適化は対象外です。
description の原文を見る
> Make .NET projects compatible with Native AOT and trimming by systematically resolving IL trim/AOT analyzer warnings. USE FOR: making projects AOT-compatible, fixing trimming warnings, resolving IL warnings (IL2026, IL2070, IL2067, IL2072, IL3050), adding DynamicallyAccessedMembers annotations, enabling IsAotCompatible. DO NOT USE FOR: publishing native AOT binaries, optimizing binary size, replacing reflection-heavy libraries with alternatives. INVOKES: no tools — pure knowledge skill.
SKILL.md 本文
dotnet-aot-compat
IL trim/AOT アナライザーの警告を体系的に解決することで、.NET プロジェクトを Native AOT およびトリミングに対応させます。
このスキルを使用すべき場合
- 「このプロジェクトを AOT 対応にする」
- 「トリミング警告を修正する」 または 「IL 警告を修正する」
- 「IL2070 / IL2067 / IL2072 / IL2026 / IL3050 警告を解決する」
- 「DynamicallyAccessedMembers アノテーションを追加する」
- 「.csproj で IsAotCompatible を有効にする」
- 「net8.0 へのアップグレード後、プロジェクトにトリミング アナライザー警告がある」
- 「リフレクション コードをトリマー用に注釈付けする」
このスキルを使用すべきではない場合
トリム/AOT アナライザーをサポートしていない .NET Framework (net4x) のみを対象とするプロジェクトには、このスキルは使用しないでください。
前提条件
net8.0 以降を対象とする既存の .NET プロジェクト (または少なくとも 1 つの net8.0+ TFM でマルチターゲット) と、対応する .NET SDK がインストールされていることが必要です。
背景: AOT 互換性とは
Native AOT と IL トリマーは、どのコードが到達可能かを判断するために静的分析を実行します。リフレクションはこの分析を破壊する可能性があります。トリマーはリフレクションが実行時にアクセスする型/メンバーを認識できないためです。IsAotCompatible プロパティはこれらの問題をビルド警告 (ILXXXX コード) としてフラグする アナライザーを有効にします。
重要なルール
❌ 警告を誤って抑制しない
- 決して IL 警告に対して
#pragma warning disableを使用しないでください。Roslyn アナライザーのビルド時の警告は非表示になりますが、IL リンカーと AOT コンパイラは問題を認識したままです。コードはトリミング/公開時に失敗します。 - 決して
[UnconditionalSuppressMessage]を使用しないでください。これはアナライザーとリンカーの両方に警告を無視するよう指示し、トリマーが安全性を検証できないことを意味します。ビルド時にエラーを発生させる方が、問題を隠して実行時に静かに破損させるよりも常に優れています。
💡 推奨されるアプローチ
[DynamicallyAccessedMembers]アノテーション を優先して、コール チェーン全体を通じて型情報をフローさせます。- アノテーション フローを破壊するパターンを排除するためのリファクタリング を優先します (例:
Typeをobject[]に経由する)。 [RequiresUnreferencedCode]/[RequiresDynamicCode]/[RequiresAssemblyFiles]を使用して、メソッドがトリミングと根本的に互換性がないことをマークし、呼び出し元に要件を伝播させます。これは問題を隠すのではなく明確に浮き上がらせます — 呼び出し元は互換性のなさを明示的に認める必要があります。
アノテーション フロー は重要
トリマーは割り当て、パラメータ渡し、戻り値を通じて [DynamicallyAccessedMembers] アノテーションを追跡します。このフロー が破壊された場合 (例: Type を object にボックス化したり、型なしコレクションに保存したり、インターフェース経由でキャストしたりする場合)、トリマーは追跡を失い、警告を発します。修正はフローを保持することであり、警告を抑制することではありません。
ステップバイステップの手順
事前にコードベースを探索しないでください。 ビルド警告は、変更が必要な正確なファイルと行を示します。タイト ループに従います: ビルド → 警告を選ぶ → そのファイルをその行で開く → 修正レシピを適用 → リビルド。警告が指摘する範囲を超えてソース ファイルを読んだり分析したりすることは無駄な労力で、タイムアウトにつながります。コンパイラーに案内させてください。
❌ ビルド前にプロジェクト構造を理解するために
find、ls、またはgrepを実行しないでください。README、ドキュメント、またはアーキテクチャ ファイルを読まないでください。最初のアクションはステップ 1 (AOT 分析を有効にする) を実行し、その後ビルドすべきです。
ステップ 1: .csproj で AOT 分析を有効にする
IsAotCompatible を追加してください。プロジェクトが net8.0+ のみをターゲットしていない場合は、TFM 条件を追加してください (AOT 分析には net8.0+ が必要):
<PropertyGroup>
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">true</IsAotCompatible>
</PropertyGroup>
これにより、互換性のある TFM に対して EnableTrimAnalyzer=true と EnableAotAnalyzer=true が自動的に設定されます。マルチターゲット プロジェクト (例: netstandard2.0;net8.0) の場合、条件により古い TFM で NETSDK1210 警告が発生しなくなります。
ステップ 2: ビルドして警告を収集する
dotnet build <project.csproj> -f <net8.0-or-later-tfm> --no-incremental 2>&1 | grep 'IL[0-9]\{4\}'
ソートして重複排除してください。一般的な警告コード:
- IL2070:
[DynamicallyAccessedMembers]が不足しているTypeパラメータへのリフレクション呼び出し - IL2067:
[DynamicallyAccessedMembers]が予想されるメソッドに注釈なしTypeを渡す - IL2072: 戻り値または抽出値のアノテーションが不足 (通常はアンボックスから)
- IL2057: 定数以外の引数を持つ
Type.GetType(string) - IL2026:
[RequiresUnreferencedCode]でマークされたメソッドを呼び出す - IL2050: COM マーシャリング パラメータを持つ P/invoke メソッド
- IL2075: 戻り値がアノテーションなしのリフレクションにフロー
- IL2091: 制約により必要な
[DynamicallyAccessedMembers]が不足している汎用引数 - IL3000:
Assembly.Locationはシングルファイル/AOT アプリで空の文字列を返す - IL3050:
[RequiresDynamicCode]でマークされたメソッドを呼び出す
ステップ 3: 警告をコードでトリアージする (全ファイルを読まない)
ステップ 2 の警告を警告コード別にグループ化してカウントしてください。個別ファイルをまだ開かないでください。 カウントによってトップ 1-2 パターンを特定してください — これらが修正戦略を駆動します:
| パターン | 典型的な修正 |
|---|---|
JsonSerializer からの多数の IL2026 + IL3050 | すぐにStrategy C に進みます — JsonSerializerContext を作成し、すべてのコール サイトをバッチ更新 |
Type パラメータの IL2070/IL2087 | 最内メソッドに [DynamicallyAccessedMembers] を追加し、外側にカスケード |
注釈なし Type を渡す IL2067 | ソースでパラメータに注釈を付ける |
ほとんどの実際のプロジェクトでは、JsonSerializer からの IL2026/IL3050 が支配的です。 警告の分析が異なるパターンを明確に示さない限り、Strategy C から開始してください。バッチ JSON 修正後、残りの警告を Strategy A–B で処理してください。Strategy D は最後の手段としてのみ使用してください。
ステップ 4: 警告を反復的に修正する (最内から外へ)
最内 のリフレクション呼び出しから外に向かって作業してください。各修正は呼び出し元への新しい警告をカスケードさせる可能性があります。
警告に駆動される。 各警告については、コンパイラーが報告したファイルと行のみを開き、パターンを特定し、以下の対応する修正レシピを適用し、移動してください。コードベースをスキャンして同様のパターンを見つけたり、完全なアーキテクチャを理解しようとしたりしないでください — コンパイラーが示すものを修正し、リビルドし、新しい警告に次の変更をガイドさせてください。小さなバッチの警告 (5-10) を修正し、その後すぐにリビルドして進捗を確認してください。
利用可能な場合はサブエージェントを使用してください。 サブエージェント (例: task ツール経由) を起動できる場合は、複数のサブエージェントを並列で ディスパッチして、異なるファイルを同時に編集してください。メイン ループはビルド、警告の解析、ディスパッチに焦点を当て、実際のファイル編集はサブエージェントに委譲してください。バッチ JSON 更新の場合、各サブエージェントに 1 つのプロンプトで 5-10 ファイルを更新するよう指示してください。2 つのビルド-修正サイクル後、残りのすべてのファイル編集をサブエージェントに並列でディスパッチしてください — ファイルの修正を順序を持たせて続行しないでください。 例:
これらのファイルをソース生成 JSON を使用するように更新してください:
src/Models/Resource.Serialization.cs、src/Models/Identity.Serialization.cs、src/Models/Plan.Serialization.cs。各ファイルで、JsonSerializer.Serialize(writer, value)をJsonSerializer.Serialize(writer, value, MyProjectJsonContext.Default.TypeName)に置き換え、JsonSerializer.Deserialize<T>(ref reader)をJsonSerializer.Deserialize(ref reader, MyProjectJsonContext.Default.TypeName)に置き換えてください。JsonSerializer コール サイトのみを編集してください。
Strategy A: [DynamicallyAccessedMembers] を追加する (推奨)
メソッドが Type パラメータに対してリフレクションを使用する場合、パラメータに注釈を付けてトリマーが必要なメンバーを伝えます:
using System.Diagnostics.CodeAnalysis;
// 前 (IL2070 を警告):
void Process(Type t) {
var method = t.GetMethod("Foo"); // トリマーは検証できない
}
// 後 (クリーン):
void Process([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {
var method = t.GetMethod("Foo"); // トリマーは公開メソッドを保持
}
パラメータに注釈を付けると、すべての呼び出し元 は適切に注釈付けされた型を渡す必要があります。これは外側にカスケードしていきます — 各呼び出し元に従い、必要に応じて注釈を付けるかリファクタリングしてください。呼び出し元のアノテーションは呼び出される側のアノテーションと同じ以上のメンバー型を含める必要があります。 呼び出される側が PublicConstructors | NonPublicConstructors を要求する場合、呼び出し元は同じまたはスーパーセットを指定する必要があります — NonPublicConstructors のみを使用すると IL2091 が生成されます。
Strategy B: アノテーション フロー を保持するようにリファクタリング
アノテーション フローがボックス化によって破壊される場合 (Type を object、object[]、または型なしコレクションに保存する場合)、リファクタリング して Type を直接渡します:
// 破損: Type が object[] にボックス化され、アノテーション喪失
void Process(object[] args) {
Type t = (Type)args[0]; // IL2072: ボックス化でアノテーション喪失
Evaluate(t, ...);
}
// 固定: Type を個別の注釈付きパラメータとして渡す
void Process(
object[] args,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type calleeType,
...) {
Evaluate(calleeType, ...); // アノテーション フローはクリーン
}
フローを破壊する一般的なパターンと修正方法:
object[]パラメータ バッグ:Typeを専用の注釈付きパラメータに抽出- Dictionary/List ストレージ: 代わりに注釈付きの型付きフィールドを使用
- インターフェース 間接化: インターフェース メソッドのパラメータに注釈を追加
- ボックス化ゲッターの付きプロパティ: プロパティの戻り値型に注釈を付ける
Strategy C: ソース生成 JSON シリアライゼーション (バッチ修正)
ほとんどの警告が JsonSerializer.Serialize/Deserialize からの IL2026/IL3050 の場合、これは単一のメカニカルな修正がバルク に適用されます:
-
影響を受けるすべてのタイプを収集 —
JsonSerializer.SerializeとJsonSerializer.Deserializeのすべてのコール サイトに grep します。シリアル化されている型 (Deserialize<T>の<T>、またはSerializeのオブジェクトのランタイム型) を抽出してください。 -
見つかったすべてのタイプに対して 1 つの
JsonSerializerContextを[JsonSerializable]で作成してください。外部パッケージからのタイプはスキップしてください (例:Azure.CoreからのResponseError— 所有していないタイプに対してはソース生成されません。外部タイプは以下の注意点 #1 で個別に処理してください。
[JsonSerializerContext]
[JsonSerializable(typeof(ManagedServiceIdentity))]
[JsonSerializable(typeof(SystemData))]
// ... 1 つのアトリビュート per あなたが所有するタイプ
// 外部パッケージ (例: ResponseError) からのタイプは追加しないでください
internal partial class MyProjectJsonContext : JsonSerializerContext { }
-
すべてのコール サイトをバッチ更新 — 各ファイルを個別に読まないでください。パターンをメカニカルに適用:
JsonSerializer.Serialize(obj)→JsonSerializer.Serialize(obj, MyProjectJsonContext.Default.TypeName)JsonSerializer.Deserialize<T>(json)→JsonSerializer.Deserialize(json, MyProjectJsonContext.Default.TypeName)
1 パスですべてのコール サイトを見つけて更新します:
# JsonSerializer 呼び出しを含むすべてのファイルを見つける grep -rl 'JsonSerializer\.\(Serialize\|Deserialize\)' src/ --include='*.cs'次に、順序を持たせて
edit呼び出しを使用して同じ変換をすべての一致ファイルに適用してください。C# コードにsedを使用しないでください —Deserialize<T>()のような汎用には角括弧とネストされた括弧があり、sed はそれをマングルします。 -
1 回ビルド して検証してください。残りの警告はシリアライゼーション以外の問題です — Strategy A–B または D で処理してください。
Strategy D: [RequiresUnreferencedCode] (最後の手段)
メソッドが静的に説明できない任意のリフレクションを基本的に必要とする場合:
[RequiresUnreferencedCode("Loads plugins by name using Assembly.Load")]
public void LoadPlugin(string assemblyName) {
var asm = Assembly.Load(assemblyName);
// ...
}
これは呼び出し元に伝播します — 呼び出し元も [RequiresUnreferencedCode] でアノテーション付けされる必要があります。慎重に使用してください。呼び出しチェーン全体をトリミング非対応としてマークします。
ステップ 5: リビルドして繰り返す
小さなバッチの修正 (5-10 警告) ごとに、--no-incremental でリビルドして新しい警告を確認してください。リビルド前にすべての警告を修正しようとしないでください — 頻繁なリビルドは早期に間違いを見つけ、カスケード警告を明らかにします。修正はカスケードしていきます — 内側のメソッドに注釈を付けると、その呼び出し元に警告が浮かび上がるかもしれません。0 Warning(s) になるまで繰り返してください。
ステップ 6: すべての TFM を検証する
すべてのターゲット フレームワークをビルドして、以下を確認してください:
- 0 IL 警告 on net8.0+ TFM
- NETSDK1210 警告なし (
IsAotCompatible条件がこれを処理) - 古い TFM でのクリーン ビルド (netstandard2.0、net472 など)
dotnet build <project.csproj> # すべての TFM をビルド
停止シグナル
- 警告パターンごとに 2-3 個の代表的なファイル以上を分析しないでください。 パターンの修正を特定した後、最初に各ファイルを読まずに、すべての一致ファイルに適用してください。
- 1 つのビルド後に修正を開始してください。 2 番目の分析パスを行わないでください — ステップ 3 トリアージの後、最も一般的な警告パターンの修正を直ちに開始してください。
- net8.0+ TFM の 0 IL 警告 を達成した後で停止してください。既にクリーンなアノテーションを最適化またはリファクタリングしないでください。
- 警告に アーキテクチャ リファクタリング がアノテーション フロー修正を超えて必要な場合 (例: シリアライゼーション層全体を置き換える)、ドキュメント化して停止してください — 大規模なサブシステムを書き直さないでください。
- 警告ごとに 3 つのビルド-修正イテレーション に制限してください。アノテーション フローが 3 回の試行後に解決しない場合は、
[RequiresUnreferencedCode]にエスカレートしてください。 - サード パーティ依存関係 の警告を追いかけないでください。これは修正できません。注記して続行してください。
- ユーザーがスコープ付き質問をした場合 (例: 「このファイルの警告を修正する」)、プロジェクト全体に展開しないでください。
古い TFM のポリフィル
netstandard2.0 または net472 を含むマルチターゲット プロジェクトの場合、DynamicallyAccessedMembersAttribute と関連型のポリフィルが必要です。references/polyfills.md を参照してください。
一般的な落とし穴
- AOT セーフ シリアライゼーションなしの外部型: 修正できない依存関係から型が来ている場合 (例:
Azure.CoreからのResponseError) でソース生成シリアライザーがない場合、Options.GetConverter<T>()はリフレクション ベースであり、IL 警告が生成されます。まず、型がIJsonModel<T>を実装するかを確認してください (Azure SDK で一般的です) — 実装する場合、JsonSerializerを完全にバイパスしてください:
// 前 (IL2026 — JsonSerializer がリフレクションを使用):
JsonSerializer.Serialize(writer, errorValue);
// 後 (AOT セーフ — IJsonModel を直接使用):
((IJsonModel<ResponseError>)errorValue).Write(writer, ModelReaderWriterOptions.Json);
// デシリアライゼーション の場合:
var error = ((IJsonModel<ResponseError>)new ResponseError()).Create(ref reader, ModelReaderWriterOptions.Json);
外部型を JsonSerializerContext に追加しないでください — 所有していないタイプに対してはソース生成されません。型が IJsonModel<T> を実装しない場合、手動の Utf8JsonReader/Utf8JsonWriter ロジックで カスタム JsonConverter<T> を記述し、[JsonSourceGenerationOptions] 経由でコンテキストに登録してください。
-
シリアライゼーション ライブラリ: ほとんどのリフレクション ベースのシリアライザー (例:
Newtonsoft.Json、XmlSerializer) は AOT 対応ではありません。JsonSerializerContextを使用したソース生成ベースのシリアライザー (例:System.Text.Json) に移行してください。移行が不可能な場合は、シリアライゼーション コール サイトを[RequiresUnreferencedCode]でマークしてください。 -
共有プロジェクト / projitems: ソースが
<Import>経由で複数のプロジェクト間で共有されている場合、共有コードに追加されたアノテーションは すべての消費プロジェクト に影響します。すべての消費者が引き続きクリーンにビルドされることを確認してください。
参照
制限 概念: トリミングについて理解する 方法: トリミング互換性
チェックリスト
-
<IsAotCompatible>と TFM 条件を .csproj に追加 - AOT アナライザー有効 (net8.0+ TFM) でビルド
- アノテーションまたはリファクタリングによってすべての IL 警告を修正
- IL 警告に
#pragma warning disableまたは[UnconditionalSuppressMessage]を使用しない - 古い TFM に必要な場合はポリフィル が存在
- すべてのターゲット フレームワークが 0 警告でビルド
- 共有/リンク ソースが兄弟プロジェクトを破損しないことを検証
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- dotnet
- リポジトリ
- dotnet/skills
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/dotnet/skills / ライセンス: MIT
関連スキル
superfluid
Superfluidプロトコルおよびそのエコシステムに関するナレッジベースです。Superfluidについて情報を検索する際は、ウェブ検索の前にこちらを参照してください。対応キーワード:Superfluid、CFA、GDA、Super App、Super Token、stream、flow rate、real-time balance、pool(member/distributor)、IDA、sentinels、liquidation、TOGA、@sfpro/sdk、semantic money、yellowpaper、whitepaper
civ-finish-quotes
実質的なタスクが真に完了した際に、文明風の儀式的な引用句を追加します。ユーザーやエージェントが機能追加、リファクタリング、分析、設計ドキュメント、プロセス改善、レポート、執筆タスクといった実際の成果物を完成させるときに、明示的な依頼がなくても使用します。短い返信や小さな修正、未完成の作業には適用しません。
nookplot
Base(Ethereum L2)上のAIエージェント向け分散型調整ネットワークです。エージェントがオンチェーンアイデンティティを登録する、コンテンツを公開する、他のエージェントにメッセージを送る、マーケットプレイスで専門家を雇う、バウンティを投稿・請求する、レピュテーションを構築する、共有プロジェクトで協業する、リサーチチャレンジを解くことでNOOKをマイニングする、キュレーションされたナレッジを備えたスタンドアロンオンチェーンエージェントをデプロイする、またはアグリーメントとリワードで収益を得る場合に利用できます。エージェントネットワーク、エージェント調整、分散型エージェント、NOOKトークン、マイニングチャレンジ、ナレッジバンドル、エージェントレピュテーション、エージェントマーケットプレイス、ERC-2771メタトランザクション、Prepare-Sign-Relay、AgentFactory、またはNookplotが言及された場合にトリガーされます。
web3-polymarket
Polygon上でのPolymarket予測市場取引統合です。認証機能(L1 EIP-712、L2 HMAC-SHA256、ビルダーヘッダー)、注文発注(GTC/GTD/FOK/FAK、バッチ、ポストオンリー、ハートビート)、市場データ(Gamma API、Data API、オーダーブック、サブグラフ)、WebSocketストリーミング(市場・ユーザー・スポーツチャネル)、CTF操作(分割、統合、償却、ネガティブリスク)、ブリッジ機能(入金、出金、マルチチェーン)、およびガスレスリレイトランザクションに対応しています。AIエージェント、自動マーケットメーカー、予測市場UI、またはPolygraph上のPolymarketと統合するアプリケーション構築時に活用できます。
ethskills
Ethereum、EVM、またはブロックチェーン関連のリクエストに対応します。スマートコントラクト、dApps、ウォレット、DeFiプロトコルの構築、監査、デプロイ、インタラクションに適用されます。Solidityの開発、コントラクトアドレス、トークン規格(ERC-20、ERC-721、ERC-4626など)、Layer 2ネットワーク(Base、Arbitrum、Optimism、zkSync、Polygon)、Uniswap、Aave、Curveなどのプロトコルとの統合をカバーします。ガスコスト、コントラクトのデシマル設定、オラクルセキュリティ、リエントランシー、MEV、ブリッジング、ウォレット管理、オンチェーンデータの取得、本番環境へのデプロイ、プロトコル進化(EIPライフサイクル、フォーク追跡、今後の変更予定)といったトピックを含みます。
xxyy-trade
このスキルは、ユーザーが「トークン購入」「トークン売却」「トークンスワップ」「暗号資産取引」「取引ステータス確認」「トランザクション照会」「トークンスキャン」「フィード」「チェーン監視」「トークン照会」「トークン詳細」「トークン安全性確認」「ウォレット一覧表示」「マイウォレット」「AIスキャン」「自動スキャン」「ツイートスキャン」「オンボーディング」「IP確認」「IPホワイトリスト」「トークン発行」「自動売却」「損切り」「利益確定」「トレーリングストップ」「保有者」「トップホルダー」「KOLホルダー」などをリクエストした場合、またはSolana/ETH/BSC/BaseチェーンでXXYYを経由した取引について言及した場合に使用します。XXYY Open APIを通じてオンチェーン取引とデータ照会を実現します。