[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-dotnet-dotnet-aot-compat":3,"mdc-tfb5ys-key":34,"related-repo-dotnet-dotnet-aot-compat":2431,"related-org-dotnet-dotnet-aot-compat":2537},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":22,"repoUrl":23,"updatedAt":24,"license":25,"forks":26,"topics":27,"repo":29,"sourceUrl":32,"mdContent":33},"dotnet-aot-compat","optimize .NET projects for Native AOT","Make .NET projects compatible with Native AOT and trimming by systematically resolving IL trim\u002FAOT 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.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"dotnet",".NET (Microsoft)","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fdotnet.png",[12,16,19],{"name":13,"slug":14,"type":15},"Performance","performance","tag",{"name":17,"slug":18,"type":15},".NET","net",{"name":20,"slug":21,"type":15},"Engineering","engineering",4576,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills","2026-07-12T08:22:57.831745","MIT",332,[28],"agent-skills",{"repoUrl":23,"stars":22,"forks":26,"topics":30,"description":31},[28],"Repository for skills to assist AI coding agents with .NET and C#","https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fskills\u002Ftree\u002FHEAD\u002Fplugins\u002Fdotnet-upgrade\u002Fskills\u002Fdotnet-aot-compat","---\nname: dotnet-aot-compat\ndescription: >\n  Make .NET projects compatible with Native AOT and trimming by systematically\n  resolving IL trim\u002FAOT analyzer warnings. USE FOR: making projects AOT-compatible,\n  fixing trimming warnings, resolving IL warnings (IL2026, IL2070, IL2067, IL2072,\n  IL3050), adding DynamicallyAccessedMembers annotations, enabling IsAotCompatible.\n  DO NOT USE FOR: publishing native AOT binaries, optimizing binary size, replacing\n  reflection-heavy libraries with alternatives.\n  INVOKES: no tools — pure knowledge skill.\nlicense: MIT\n---\n\n# dotnet-aot-compat\n\nMake .NET projects compatible with Native AOT and trimming by systematically resolving all IL trim\u002FAOT analyzer warnings.\n\n## When to Use This Skill\n\n- **\"Make this project AOT-compatible\"**\n- **\"Fix trimming warnings\"** or **\"fix IL warnings\"**\n- **\"Resolve IL2070 \u002F IL2067 \u002F IL2072 \u002F IL2026 \u002F IL3050 warnings\"**\n- **\"Add DynamicallyAccessedMembers annotations\"**\n- **\"Enable IsAotCompatible in my .csproj\"**\n- **\"My project has trim analyzer warnings after upgrading to net8.0\"**\n- **\"Annotate reflection code for the trimmer\"**\n\n## When Not to Use This Skill\n\nDo not use this skill when the project exclusively targets .NET Framework (net4x), which does not support the trim\u002FAOT analyzers.\n\n## Prerequisites\n\nAn existing .NET project targeting net8.0 or later (or multi-targeting with at least one net8.0+ TFM) and the corresponding .NET SDK installed.\n\n## Background: What AOT Compatibility Means\n\nNative AOT and the IL trimmer perform static analysis to determine what code is reachable. Reflection can break this analysis because the trimmer can't see what types\u002Fmembers are accessed at runtime. The `IsAotCompatible` property enables analyzers that flag these issues as build warnings (ILXXXX codes).\n\n## Critical Rules\n\n### ❌ Never suppress warnings incorrectly\n\n- **NEVER** use `#pragma warning disable` for IL warnings. It hides warnings from the Roslyn analyzer at build time, but the IL linker and AOT compiler still see the issue. The code will fail at trim\u002Fpublish time.\n- **NEVER** use `[UnconditionalSuppressMessage]`. It tells both the analyzer AND the linker to ignore the warning, meaning the trimmer cannot verify safety. Raising an error at build time is always preferable to hiding the issue and having it silently break at runtime.\n\n### 💡 Preferred approaches\n\n- **Prefer** `[DynamicallyAccessedMembers]` annotations to flow type information through the call chain.\n- **Prefer** refactoring to eliminate patterns that break annotation flow (e.g., boxing `Type` through `object[]`).\n- **Use** `[RequiresUnreferencedCode]` \u002F `[RequiresDynamicCode]` \u002F `[RequiresAssemblyFiles]` to mark methods as fundamentally incompatible with trimming, propagating the requirement to callers. This surfaces the issue clearly rather than hiding it — callers must explicitly acknowledge the incompatibility.\n\n### Annotation flow is key\n\nThe trimmer tracks `[DynamicallyAccessedMembers]` annotations through assignments, parameter passing, and return values. If this flow is broken (e.g., by boxing a `Type` into `object`, storing in an untyped collection, or casting through interfaces), the trimmer loses track and warns. The fix is to preserve the flow, not suppress the warning.\n\n## Step-by-Step Procedure\n\n> **Do not explore the codebase up-front.** The build warnings tell you exactly which files and lines need changes. Follow a tight loop: **build → pick a warning → open that file at that line → apply the fix recipe → rebuild**. Reading or analyzing source files beyond what a specific warning points you to is wasted effort and leads to timeouts. Let the compiler guide you.\n>\n> ❌ Do NOT run `find`, `ls`, or `grep` to understand the project structure before building. Do NOT read README, docs, or architecture files. Your first action should be Step 1 (enable AOT analysis), then build.\n\n### Step 1: Enable AOT analysis in the .csproj\n\nAdd `IsAotCompatible`. If the project doesn't exclusively target net8.0+, add a TFM condition (AOT analysis requires net8.0+):\n\n```xml\n\u003CPropertyGroup>\n  \u003CIsAotCompatible Condition=\"$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))\">true\u003C\u002FIsAotCompatible>\n\u003C\u002FPropertyGroup>\n```\n\nThis automatically sets `EnableTrimAnalyzer=true` and `EnableAotAnalyzer=true` for compatible TFMs. For multi-targeting projects (e.g., `netstandard2.0;net8.0`), the condition ensures no `NETSDK1210` warnings on older TFMs.\n\n### Step 2: Build and collect warnings\n\n```bash\ndotnet build \u003Cproject.csproj> -f \u003Cnet8.0-or-later-tfm> --no-incremental 2>&1 | grep 'IL[0-9]\\{4\\}'\n```\n\nSort and deduplicate. Common warning codes:\n- **IL2070**: Reflection call on a `Type` parameter missing `[DynamicallyAccessedMembers]`\n- **IL2067**: Passing an unannotated `Type` to a method expecting `[DynamicallyAccessedMembers]`\n- **IL2072**: Return value or extracted value missing annotation (often from unboxing)\n- **IL2057**: `Type.GetType(string)` with a non-constant argument\n- **IL2026**: Calling a method marked `[RequiresUnreferencedCode]`\n- **IL2050**: P\u002Finvoke method with COM marshalling parameters\n- **IL2075**: Return value flows into reflection without annotation\n- **IL2091**: Generic argument missing `[DynamicallyAccessedMembers]` required by constraint\n- **IL3000**: `Assembly.Location` returns empty string in single-file\u002FAOT apps\n- **IL3050**: Calling a method marked `[RequiresDynamicCode]`\n\n### Step 3: Triage warnings by code (do NOT read every file)\n\nGroup the warnings from Step 2 by warning code and count them. **Do not open individual files yet.** Identify the top 1-2 patterns by count — these drive your fix strategy:\n\n| Pattern | Typical fix |\n|---------|-------------|\n| Many IL2026 + IL3050 from `JsonSerializer` | **Go to Strategy C immediately** — create a `JsonSerializerContext`, then batch-update all call sites |\n| IL2070\u002FIL2087 on `Type` parameters | Add `[DynamicallyAccessedMembers]` to the innermost method, then cascade outward |\n| IL2067 passing unannotated `Type` | Annotate the parameter at the source |\n\n**In most real projects, IL2026\u002FIL3050 from JsonSerializer dominate.** Start with Strategy C unless the warning breakdown clearly shows otherwise. After the batch JSON fix, handle remaining warnings with Strategies A–B. Only use Strategy D as a last resort.\n\n### Step 4: Fix warnings iteratively (innermost first)\n\nWork from the **innermost** reflection call outward. Each fix may cascade new warnings to callers.\n\n**Stay warning-driven.** For each warning, open only the file and line the compiler reported, identify the pattern, apply the matching fix recipe below, and move on. Do not scan the codebase for similar patterns or try to understand the full architecture — fix what the compiler tells you, rebuild, and let new warnings guide the next change. Fix a small batch of warnings (5-10), then rebuild immediately to check progress.\n\n**Use sub-agents when available.** If you can launch sub-agents (e.g., via a `task` tool), dispatch **multiple sub-agents in parallel** to edit different files simultaneously. Keep the main loop focused on building, parsing warnings, and dispatching — delegate actual file edits to sub-agents. For batch JSON updates, give each sub-agent 5-10 files to update in one prompt. **After 2 build-fix cycles, dispatch all remaining file edits to sub-agents in parallel — do not continue fixing files sequentially.** Example:\n\n> Update these files to use source-generated JSON: `src\u002FModels\u002FResource.Serialization.cs`, `src\u002FModels\u002FIdentity.Serialization.cs`, `src\u002FModels\u002FPlan.Serialization.cs`. In each file, replace `JsonSerializer.Serialize(writer, value)` with `JsonSerializer.Serialize(writer, value, MyProjectJsonContext.Default.TypeName)` and `JsonSerializer.Deserialize\u003CT>(ref reader)` with `JsonSerializer.Deserialize(ref reader, MyProjectJsonContext.Default.TypeName)`. Only edit the JsonSerializer call sites.\n\n#### Strategy A: Add `[DynamicallyAccessedMembers]` (preferred)\n\nWhen a method uses reflection on a `Type` parameter, annotate the parameter to tell the trimmer what members are needed:\n\n```csharp\nusing System.Diagnostics.CodeAnalysis;\n\n\u002F\u002F Before (warns IL2070):\nvoid Process(Type t) {\n    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer can't verify\n}\n\n\u002F\u002F After (clean):\nvoid Process([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {\n    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer preserves public methods\n}\n```\n\nWhen you annotate a parameter, **all callers** must now pass properly annotated types. This cascades outward — follow each caller and annotate or refactor as needed. **The caller's annotation must include at least the same member types as the callee's.** If the callee requires `PublicConstructors | NonPublicConstructors`, the caller must specify the same or a superset — using only `NonPublicConstructors` will produce IL2091.\n\n#### Strategy B: Refactor to preserve annotation flow\n\nWhen annotation flow is broken by boxing (storing `Type` in `object`, `object[]`, or untyped collections), **refactor** to pass the `Type` directly:\n\n```csharp\n\u002F\u002F BROKEN: Type boxed into object[], annotation lost\nvoid Process(object[] args) {\n    Type t = (Type)args[0];  \u002F\u002F IL2072: annotation lost through boxing\n    Evaluate(t, ...);\n}\n\n\u002F\u002F FIXED: Pass Type as a separate, annotated parameter\nvoid Process(\n    object[] args,\n    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type calleeType,\n    ...) {\n    Evaluate(calleeType, ...);  \u002F\u002F annotation flows cleanly\n}\n```\n\nCommon patterns that break flow and how to fix them:\n- **`object[]` parameter bags**: Extract the `Type` into a dedicated annotated parameter\n- **Dictionary\u002FList storage**: Use a typed field with annotation instead\n- **Interface indirection**: Add annotation to the interface method's parameter\n- **Property with boxing getter**: Annotate the property's return type\n\n#### Strategy C: Source-generated JSON serialization (batch fix)\n\nWhen most warnings are IL2026\u002FIL3050 from `JsonSerializer.Serialize`\u002F`Deserialize`, this is a single mechanical fix applied in bulk:\n\n1. **Collect affected types** — grep for all `JsonSerializer.Serialize` and `JsonSerializer.Deserialize` call sites. Extract the type being serialized (the `\u003CT>` in `Deserialize\u003CT>`, or the runtime type of the object in `Serialize`).\n\n2. **Create one `JsonSerializerContext`** with `[JsonSerializable]` for every type found. **Skip types from external packages** (e.g., `ResponseError` from `Azure.Core`) — they won't source-generate for types you don't own. Handle external types separately via Gotcha #1 below.\n\n```csharp\n[JsonSerializerContext]\n[JsonSerializable(typeof(ManagedServiceIdentity))]\n[JsonSerializable(typeof(SystemData))]\n\u002F\u002F ... one attribute per type YOU OWN\n\u002F\u002F Do NOT add types from external packages (e.g., ResponseError)\ninternal partial class MyProjectJsonContext : JsonSerializerContext { }\n```\n\n3. **Batch-update all call sites** — do not read each file individually. Apply the pattern mechanically:\n   - `JsonSerializer.Serialize(obj)` → `JsonSerializer.Serialize(obj, MyProjectJsonContext.Default.TypeName)`\n   - `JsonSerializer.Deserialize\u003CT>(json)` → `JsonSerializer.Deserialize(json, MyProjectJsonContext.Default.TypeName)`\n\n   Find and update all call sites in one pass:\n   ```bash\n   # Find all files with JsonSerializer calls\n   grep -rl 'JsonSerializer\\.\\(Serialize\\|Deserialize\\)' src\u002F --include='*.cs'\n   ```\n   Then use sequential `edit` calls to apply the same transformation to every matching file. **Do not use `sed` for C# code** — generics like `Deserialize\u003CT>()` have angle brackets and nested parentheses that sed will mangle.\n\n4. **Build once** to verify. Remaining warnings will be non-serialization issues — handle those with Strategies A–B or D.\n\n#### Strategy D: `[RequiresUnreferencedCode]` (last resort)\n\nWhen a method fundamentally requires arbitrary reflection that cannot be statically described:\n\n```csharp\n[RequiresUnreferencedCode(\"Loads plugins by name using Assembly.Load\")]\npublic void LoadPlugin(string assemblyName) {\n    var asm = Assembly.Load(assemblyName);\n    \u002F\u002F ...\n}\n```\n\nThis propagates to callers — they must also be annotated with `[RequiresUnreferencedCode]`. Use sparingly; it marks the entire call chain as trim-incompatible.\n\n### Step 5: Rebuild and repeat\n\nAfter each small batch of fixes (5-10 warnings), rebuild with `--no-incremental` and check for new warnings. **Do not attempt to fix all warnings before rebuilding** — frequent rebuilds catch mistakes early and reveal cascading warnings. Fixes cascade — annotating an inner method may surface warnings in its callers. Repeat until `0 Warning(s)`.\n\n### Step 6: Validate all TFMs\n\nBuild all target frameworks to ensure:\n- **0 IL warnings** on net8.0+ TFMs\n- **No NETSDK1210 warnings** (the `IsAotCompatible` condition handles this)\n- **Clean builds** on older TFMs (netstandard2.0, net472, etc.)\n\n```bash\ndotnet build \u003Cproject.csproj>  # builds all TFMs\n```\n\n## Stop Signals\n\n- **Do not analyze more than 2-3 representative files per warning pattern.** After identifying the fix for a pattern, apply it to all matching files without reading each one first.\n- **Start fixing after one build.** Do not do a second analysis pass — begin implementing fixes for the most common warning pattern immediately after Step 3 triage.\n- Stop after achieving **0 IL warnings** for net8.0+ TFMs. Don't optimize or refactor already-clean annotations.\n- If a warning requires **architectural refactoring** beyond annotation flow fixes (e.g., replacing an entire serialization layer), document it and stop — don't rewrite large subsystems.\n- Limit to **3 build-fix iterations** per warning. If annotation flow doesn't resolve it after 3 attempts, escalate to `[RequiresUnreferencedCode]`.\n- Don't chase warnings in **third-party dependencies** you can't modify. Note them and move on.\n- If the user asked a scoped question (e.g., \"fix warnings in this file\"), don't expand to the entire project.\n\n## Polyfills for Older TFMs\n\nFor multi-targeting projects that include netstandard2.0 or net472, you need polyfills for `DynamicallyAccessedMembersAttribute` and related types. See [references\u002Fpolyfills.md](references\u002Fpolyfills.md).\n\n## Common Gotchas\n\n1. **External types without AOT-safe serialization**: When a type comes from a dependency you can't modify (e.g., `ResponseError` from `Azure.Core`) and it lacks a source-generated serializer, `Options.GetConverter\u003CT>()` is reflection-based and will produce IL warnings. First check if the type implements `IJsonModel\u003CT>` (common in Azure SDK) — if so, bypass `JsonSerializer` entirely:\n\n```csharp\n\u002F\u002F Before (IL2026 — JsonSerializer uses reflection):\nJsonSerializer.Serialize(writer, errorValue);\n\n\u002F\u002F After (AOT-safe — uses IJsonModel directly):\n((IJsonModel\u003CResponseError>)errorValue).Write(writer, ModelReaderWriterOptions.Json);\n\n\u002F\u002F For deserialization:\nvar error = ((IJsonModel\u003CResponseError>)new ResponseError()).Create(ref reader, ModelReaderWriterOptions.Json);\n```\n\nDo **not** add the external type to your `JsonSerializerContext` — it won't source-generate for types you don't own. If the type doesn't implement `IJsonModel\u003CT>`, write a custom `JsonConverter\u003CT>` with manual `Utf8JsonReader`\u002F`Utf8JsonWriter` logic and register it via `[JsonSourceGenerationOptions]` on your context.\n\n2. **Serialization libraries**: Most reflection-based serializers (e.g., `Newtonsoft.Json`, `XmlSerializer`) are not AOT-compatible. Migrate to a source-generation-based serializer such as `System.Text.Json` with a `JsonSerializerContext`. If migration is not feasible, mark the serialization call site with `[RequiresUnreferencedCode]`.\n\n3. **Shared projects \u002F projitems**: When source is shared between multiple projects via `\u003CImport>`, annotations added to shared code affect ALL consuming projects. Verify that all consumers still build cleanly.\n\n## References\n\n[Limitations](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Fnative-aot\u002F?tabs=windows%2Cnet8#limitations-of-native-aot-deployment)\n[Conceptual: Understanding trimming](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Ftrimming\u002Ftrimming-concepts)\n[How-to: trim compat](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Ftrimming\u002Ffixing-warnings)\n\n## Checklist\n\n- [ ] Added `\u003CIsAotCompatible>` with TFM condition to .csproj\n- [ ] Built with AOT analyzers enabled (net8.0+ TFM)\n- [ ] Fixed all IL warnings via annotations or refactoring\n- [ ] No `#pragma warning disable` or `[UnconditionalSuppressMessage]` used for any IL warning\n- [ ] Polyfills present for older TFMs if needed\n- [ ] All target frameworks build with 0 warnings\n- [ ] Verified shared\u002Flinked source doesn't break sibling projects\n",{"data":35,"body":36},{"name":4,"description":6,"license":25},{"type":37,"children":38},"root",[39,46,52,59,128,134,139,145,150,156,170,176,183,220,226,304,310,337,343,393,399,411,451,488,494,597,602,760,766,778,882,892,898,910,920,952,1012,1026,1038,1142,1177,1183,1222,1332,1337,1392,1398,1419,1514,1569,1735,1748,1753,1799,1811,1817,1845,1851,1856,1896,1935,1941,2022,2028,2048,2054,2103,2172,2229,2296,2302,2327,2333,2425],{"type":40,"tag":41,"props":42,"children":43},"element","h1",{"id":4},[44],{"type":45,"value":4},"text",{"type":40,"tag":47,"props":48,"children":49},"p",{},[50],{"type":45,"value":51},"Make .NET projects compatible with Native AOT and trimming by systematically resolving all IL trim\u002FAOT analyzer warnings.",{"type":40,"tag":53,"props":54,"children":56},"h2",{"id":55},"when-to-use-this-skill",[57],{"type":45,"value":58},"When to Use This Skill",{"type":40,"tag":60,"props":61,"children":62},"ul",{},[63,73,88,96,104,112,120],{"type":40,"tag":64,"props":65,"children":66},"li",{},[67],{"type":40,"tag":68,"props":69,"children":70},"strong",{},[71],{"type":45,"value":72},"\"Make this project AOT-compatible\"",{"type":40,"tag":64,"props":74,"children":75},{},[76,81,83],{"type":40,"tag":68,"props":77,"children":78},{},[79],{"type":45,"value":80},"\"Fix trimming warnings\"",{"type":45,"value":82}," or ",{"type":40,"tag":68,"props":84,"children":85},{},[86],{"type":45,"value":87},"\"fix IL warnings\"",{"type":40,"tag":64,"props":89,"children":90},{},[91],{"type":40,"tag":68,"props":92,"children":93},{},[94],{"type":45,"value":95},"\"Resolve IL2070 \u002F IL2067 \u002F IL2072 \u002F IL2026 \u002F IL3050 warnings\"",{"type":40,"tag":64,"props":97,"children":98},{},[99],{"type":40,"tag":68,"props":100,"children":101},{},[102],{"type":45,"value":103},"\"Add DynamicallyAccessedMembers annotations\"",{"type":40,"tag":64,"props":105,"children":106},{},[107],{"type":40,"tag":68,"props":108,"children":109},{},[110],{"type":45,"value":111},"\"Enable IsAotCompatible in my .csproj\"",{"type":40,"tag":64,"props":113,"children":114},{},[115],{"type":40,"tag":68,"props":116,"children":117},{},[118],{"type":45,"value":119},"\"My project has trim analyzer warnings after upgrading to net8.0\"",{"type":40,"tag":64,"props":121,"children":122},{},[123],{"type":40,"tag":68,"props":124,"children":125},{},[126],{"type":45,"value":127},"\"Annotate reflection code for the trimmer\"",{"type":40,"tag":53,"props":129,"children":131},{"id":130},"when-not-to-use-this-skill",[132],{"type":45,"value":133},"When Not to Use This Skill",{"type":40,"tag":47,"props":135,"children":136},{},[137],{"type":45,"value":138},"Do not use this skill when the project exclusively targets .NET Framework (net4x), which does not support the trim\u002FAOT analyzers.",{"type":40,"tag":53,"props":140,"children":142},{"id":141},"prerequisites",[143],{"type":45,"value":144},"Prerequisites",{"type":40,"tag":47,"props":146,"children":147},{},[148],{"type":45,"value":149},"An existing .NET project targeting net8.0 or later (or multi-targeting with at least one net8.0+ TFM) and the corresponding .NET SDK installed.",{"type":40,"tag":53,"props":151,"children":153},{"id":152},"background-what-aot-compatibility-means",[154],{"type":45,"value":155},"Background: What AOT Compatibility Means",{"type":40,"tag":47,"props":157,"children":158},{},[159,161,168],{"type":45,"value":160},"Native AOT and the IL trimmer perform static analysis to determine what code is reachable. Reflection can break this analysis because the trimmer can't see what types\u002Fmembers are accessed at runtime. The ",{"type":40,"tag":162,"props":163,"children":165},"code",{"className":164},[],[166],{"type":45,"value":167},"IsAotCompatible",{"type":45,"value":169}," property enables analyzers that flag these issues as build warnings (ILXXXX codes).",{"type":40,"tag":53,"props":171,"children":173},{"id":172},"critical-rules",[174],{"type":45,"value":175},"Critical Rules",{"type":40,"tag":177,"props":178,"children":180},"h3",{"id":179},"never-suppress-warnings-incorrectly",[181],{"type":45,"value":182},"❌ Never suppress warnings incorrectly",{"type":40,"tag":60,"props":184,"children":185},{},[186,204],{"type":40,"tag":64,"props":187,"children":188},{},[189,194,196,202],{"type":40,"tag":68,"props":190,"children":191},{},[192],{"type":45,"value":193},"NEVER",{"type":45,"value":195}," use ",{"type":40,"tag":162,"props":197,"children":199},{"className":198},[],[200],{"type":45,"value":201},"#pragma warning disable",{"type":45,"value":203}," for IL warnings. It hides warnings from the Roslyn analyzer at build time, but the IL linker and AOT compiler still see the issue. The code will fail at trim\u002Fpublish time.",{"type":40,"tag":64,"props":205,"children":206},{},[207,211,212,218],{"type":40,"tag":68,"props":208,"children":209},{},[210],{"type":45,"value":193},{"type":45,"value":195},{"type":40,"tag":162,"props":213,"children":215},{"className":214},[],[216],{"type":45,"value":217},"[UnconditionalSuppressMessage]",{"type":45,"value":219},". It tells both the analyzer AND the linker to ignore the warning, meaning the trimmer cannot verify safety. Raising an error at build time is always preferable to hiding the issue and having it silently break at runtime.",{"type":40,"tag":177,"props":221,"children":223},{"id":222},"preferred-approaches",[224],{"type":45,"value":225},"💡 Preferred approaches",{"type":40,"tag":60,"props":227,"children":228},{},[229,247,272],{"type":40,"tag":64,"props":230,"children":231},{},[232,237,239,245],{"type":40,"tag":68,"props":233,"children":234},{},[235],{"type":45,"value":236},"Prefer",{"type":45,"value":238}," ",{"type":40,"tag":162,"props":240,"children":242},{"className":241},[],[243],{"type":45,"value":244},"[DynamicallyAccessedMembers]",{"type":45,"value":246}," annotations to flow type information through the call chain.",{"type":40,"tag":64,"props":248,"children":249},{},[250,254,256,262,264,270],{"type":40,"tag":68,"props":251,"children":252},{},[253],{"type":45,"value":236},{"type":45,"value":255}," refactoring to eliminate patterns that break annotation flow (e.g., boxing ",{"type":40,"tag":162,"props":257,"children":259},{"className":258},[],[260],{"type":45,"value":261},"Type",{"type":45,"value":263}," through ",{"type":40,"tag":162,"props":265,"children":267},{"className":266},[],[268],{"type":45,"value":269},"object[]",{"type":45,"value":271},").",{"type":40,"tag":64,"props":273,"children":274},{},[275,280,281,287,289,295,296,302],{"type":40,"tag":68,"props":276,"children":277},{},[278],{"type":45,"value":279},"Use",{"type":45,"value":238},{"type":40,"tag":162,"props":282,"children":284},{"className":283},[],[285],{"type":45,"value":286},"[RequiresUnreferencedCode]",{"type":45,"value":288}," \u002F ",{"type":40,"tag":162,"props":290,"children":292},{"className":291},[],[293],{"type":45,"value":294},"[RequiresDynamicCode]",{"type":45,"value":288},{"type":40,"tag":162,"props":297,"children":299},{"className":298},[],[300],{"type":45,"value":301},"[RequiresAssemblyFiles]",{"type":45,"value":303}," to mark methods as fundamentally incompatible with trimming, propagating the requirement to callers. This surfaces the issue clearly rather than hiding it — callers must explicitly acknowledge the incompatibility.",{"type":40,"tag":177,"props":305,"children":307},{"id":306},"annotation-flow-is-key",[308],{"type":45,"value":309},"Annotation flow is key",{"type":40,"tag":47,"props":311,"children":312},{},[313,315,320,322,327,329,335],{"type":45,"value":314},"The trimmer tracks ",{"type":40,"tag":162,"props":316,"children":318},{"className":317},[],[319],{"type":45,"value":244},{"type":45,"value":321}," annotations through assignments, parameter passing, and return values. If this flow is broken (e.g., by boxing a ",{"type":40,"tag":162,"props":323,"children":325},{"className":324},[],[326],{"type":45,"value":261},{"type":45,"value":328}," into ",{"type":40,"tag":162,"props":330,"children":332},{"className":331},[],[333],{"type":45,"value":334},"object",{"type":45,"value":336},", storing in an untyped collection, or casting through interfaces), the trimmer loses track and warns. The fix is to preserve the flow, not suppress the warning.",{"type":40,"tag":53,"props":338,"children":340},{"id":339},"step-by-step-procedure",[341],{"type":45,"value":342},"Step-by-Step Procedure",{"type":40,"tag":344,"props":345,"children":346},"blockquote",{},[347,364],{"type":40,"tag":47,"props":348,"children":349},{},[350,355,357,362],{"type":40,"tag":68,"props":351,"children":352},{},[353],{"type":45,"value":354},"Do not explore the codebase up-front.",{"type":45,"value":356}," The build warnings tell you exactly which files and lines need changes. Follow a tight loop: ",{"type":40,"tag":68,"props":358,"children":359},{},[360],{"type":45,"value":361},"build → pick a warning → open that file at that line → apply the fix recipe → rebuild",{"type":45,"value":363},". Reading or analyzing source files beyond what a specific warning points you to is wasted effort and leads to timeouts. Let the compiler guide you.",{"type":40,"tag":47,"props":365,"children":366},{},[367,369,375,377,383,385,391],{"type":45,"value":368},"❌ Do NOT run ",{"type":40,"tag":162,"props":370,"children":372},{"className":371},[],[373],{"type":45,"value":374},"find",{"type":45,"value":376},", ",{"type":40,"tag":162,"props":378,"children":380},{"className":379},[],[381],{"type":45,"value":382},"ls",{"type":45,"value":384},", or ",{"type":40,"tag":162,"props":386,"children":388},{"className":387},[],[389],{"type":45,"value":390},"grep",{"type":45,"value":392}," to understand the project structure before building. Do NOT read README, docs, or architecture files. Your first action should be Step 1 (enable AOT analysis), then build.",{"type":40,"tag":177,"props":394,"children":396},{"id":395},"step-1-enable-aot-analysis-in-the-csproj",[397],{"type":45,"value":398},"Step 1: Enable AOT analysis in the .csproj",{"type":40,"tag":47,"props":400,"children":401},{},[402,404,409],{"type":45,"value":403},"Add ",{"type":40,"tag":162,"props":405,"children":407},{"className":406},[],[408],{"type":45,"value":167},{"type":45,"value":410},". If the project doesn't exclusively target net8.0+, add a TFM condition (AOT analysis requires net8.0+):",{"type":40,"tag":412,"props":413,"children":418},"pre",{"className":414,"code":415,"language":416,"meta":417,"style":417},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CPropertyGroup>\n  \u003CIsAotCompatible Condition=\"$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))\">true\u003C\u002FIsAotCompatible>\n\u003C\u002FPropertyGroup>\n","xml","",[419],{"type":40,"tag":162,"props":420,"children":421},{"__ignoreMap":417},[422,433,442],{"type":40,"tag":423,"props":424,"children":427},"span",{"class":425,"line":426},"line",1,[428],{"type":40,"tag":423,"props":429,"children":430},{},[431],{"type":45,"value":432},"\u003CPropertyGroup>\n",{"type":40,"tag":423,"props":434,"children":436},{"class":425,"line":435},2,[437],{"type":40,"tag":423,"props":438,"children":439},{},[440],{"type":45,"value":441},"  \u003CIsAotCompatible Condition=\"$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))\">true\u003C\u002FIsAotCompatible>\n",{"type":40,"tag":423,"props":443,"children":445},{"class":425,"line":444},3,[446],{"type":40,"tag":423,"props":447,"children":448},{},[449],{"type":45,"value":450},"\u003C\u002FPropertyGroup>\n",{"type":40,"tag":47,"props":452,"children":453},{},[454,456,462,464,470,472,478,480,486],{"type":45,"value":455},"This automatically sets ",{"type":40,"tag":162,"props":457,"children":459},{"className":458},[],[460],{"type":45,"value":461},"EnableTrimAnalyzer=true",{"type":45,"value":463}," and ",{"type":40,"tag":162,"props":465,"children":467},{"className":466},[],[468],{"type":45,"value":469},"EnableAotAnalyzer=true",{"type":45,"value":471}," for compatible TFMs. For multi-targeting projects (e.g., ",{"type":40,"tag":162,"props":473,"children":475},{"className":474},[],[476],{"type":45,"value":477},"netstandard2.0;net8.0",{"type":45,"value":479},"), the condition ensures no ",{"type":40,"tag":162,"props":481,"children":483},{"className":482},[],[484],{"type":45,"value":485},"NETSDK1210",{"type":45,"value":487}," warnings on older TFMs.",{"type":40,"tag":177,"props":489,"children":491},{"id":490},"step-2-build-and-collect-warnings",[492],{"type":45,"value":493},"Step 2: Build and collect warnings",{"type":40,"tag":412,"props":495,"children":499},{"className":496,"code":497,"language":498,"meta":417,"style":417},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dotnet build \u003Cproject.csproj> -f \u003Cnet8.0-or-later-tfm> --no-incremental 2>&1 | grep 'IL[0-9]\\{4\\}'\n","bash",[500],{"type":40,"tag":162,"props":501,"children":502},{"__ignoreMap":417},[503],{"type":40,"tag":423,"props":504,"children":505},{"class":425,"line":426},[506,511,517,523,528,534,539,544,548,553,558,562,567,572,577,582,587,592],{"type":40,"tag":423,"props":507,"children":509},{"style":508},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[510],{"type":45,"value":8},{"type":40,"tag":423,"props":512,"children":514},{"style":513},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[515],{"type":45,"value":516}," build",{"type":40,"tag":423,"props":518,"children":520},{"style":519},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[521],{"type":45,"value":522}," \u003C",{"type":40,"tag":423,"props":524,"children":525},{"style":513},[526],{"type":45,"value":527},"project.cspro",{"type":40,"tag":423,"props":529,"children":531},{"style":530},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[532],{"type":45,"value":533},"j",{"type":40,"tag":423,"props":535,"children":536},{"style":519},[537],{"type":45,"value":538},">",{"type":40,"tag":423,"props":540,"children":541},{"style":513},[542],{"type":45,"value":543}," -f",{"type":40,"tag":423,"props":545,"children":546},{"style":519},[547],{"type":45,"value":522},{"type":40,"tag":423,"props":549,"children":550},{"style":513},[551],{"type":45,"value":552},"net8.0-or-later-tf",{"type":40,"tag":423,"props":554,"children":555},{"style":530},[556],{"type":45,"value":557},"m",{"type":40,"tag":423,"props":559,"children":560},{"style":519},[561],{"type":45,"value":538},{"type":40,"tag":423,"props":563,"children":564},{"style":513},[565],{"type":45,"value":566}," --no-incremental",{"type":40,"tag":423,"props":568,"children":569},{"style":519},[570],{"type":45,"value":571}," 2>&1",{"type":40,"tag":423,"props":573,"children":574},{"style":519},[575],{"type":45,"value":576}," |",{"type":40,"tag":423,"props":578,"children":579},{"style":508},[580],{"type":45,"value":581}," grep",{"type":40,"tag":423,"props":583,"children":584},{"style":519},[585],{"type":45,"value":586}," '",{"type":40,"tag":423,"props":588,"children":589},{"style":513},[590],{"type":45,"value":591},"IL[0-9]\\{4\\}",{"type":40,"tag":423,"props":593,"children":594},{"style":519},[595],{"type":45,"value":596},"'\n",{"type":40,"tag":47,"props":598,"children":599},{},[600],{"type":45,"value":601},"Sort and deduplicate. Common warning codes:",{"type":40,"tag":60,"props":603,"children":604},{},[605,627,649,659,677,692,702,712,729,746],{"type":40,"tag":64,"props":606,"children":607},{},[608,613,615,620,622],{"type":40,"tag":68,"props":609,"children":610},{},[611],{"type":45,"value":612},"IL2070",{"type":45,"value":614},": Reflection call on a ",{"type":40,"tag":162,"props":616,"children":618},{"className":617},[],[619],{"type":45,"value":261},{"type":45,"value":621}," parameter missing ",{"type":40,"tag":162,"props":623,"children":625},{"className":624},[],[626],{"type":45,"value":244},{"type":40,"tag":64,"props":628,"children":629},{},[630,635,637,642,644],{"type":40,"tag":68,"props":631,"children":632},{},[633],{"type":45,"value":634},"IL2067",{"type":45,"value":636},": Passing an unannotated ",{"type":40,"tag":162,"props":638,"children":640},{"className":639},[],[641],{"type":45,"value":261},{"type":45,"value":643}," to a method expecting ",{"type":40,"tag":162,"props":645,"children":647},{"className":646},[],[648],{"type":45,"value":244},{"type":40,"tag":64,"props":650,"children":651},{},[652,657],{"type":40,"tag":68,"props":653,"children":654},{},[655],{"type":45,"value":656},"IL2072",{"type":45,"value":658},": Return value or extracted value missing annotation (often from unboxing)",{"type":40,"tag":64,"props":660,"children":661},{},[662,667,669,675],{"type":40,"tag":68,"props":663,"children":664},{},[665],{"type":45,"value":666},"IL2057",{"type":45,"value":668},": ",{"type":40,"tag":162,"props":670,"children":672},{"className":671},[],[673],{"type":45,"value":674},"Type.GetType(string)",{"type":45,"value":676}," with a non-constant argument",{"type":40,"tag":64,"props":678,"children":679},{},[680,685,687],{"type":40,"tag":68,"props":681,"children":682},{},[683],{"type":45,"value":684},"IL2026",{"type":45,"value":686},": Calling a method marked ",{"type":40,"tag":162,"props":688,"children":690},{"className":689},[],[691],{"type":45,"value":286},{"type":40,"tag":64,"props":693,"children":694},{},[695,700],{"type":40,"tag":68,"props":696,"children":697},{},[698],{"type":45,"value":699},"IL2050",{"type":45,"value":701},": P\u002Finvoke method with COM marshalling parameters",{"type":40,"tag":64,"props":703,"children":704},{},[705,710],{"type":40,"tag":68,"props":706,"children":707},{},[708],{"type":45,"value":709},"IL2075",{"type":45,"value":711},": Return value flows into reflection without annotation",{"type":40,"tag":64,"props":713,"children":714},{},[715,720,722,727],{"type":40,"tag":68,"props":716,"children":717},{},[718],{"type":45,"value":719},"IL2091",{"type":45,"value":721},": Generic argument missing ",{"type":40,"tag":162,"props":723,"children":725},{"className":724},[],[726],{"type":45,"value":244},{"type":45,"value":728}," required by constraint",{"type":40,"tag":64,"props":730,"children":731},{},[732,737,738,744],{"type":40,"tag":68,"props":733,"children":734},{},[735],{"type":45,"value":736},"IL3000",{"type":45,"value":668},{"type":40,"tag":162,"props":739,"children":741},{"className":740},[],[742],{"type":45,"value":743},"Assembly.Location",{"type":45,"value":745}," returns empty string in single-file\u002FAOT apps",{"type":40,"tag":64,"props":747,"children":748},{},[749,754,755],{"type":40,"tag":68,"props":750,"children":751},{},[752],{"type":45,"value":753},"IL3050",{"type":45,"value":686},{"type":40,"tag":162,"props":756,"children":758},{"className":757},[],[759],{"type":45,"value":294},{"type":40,"tag":177,"props":761,"children":763},{"id":762},"step-3-triage-warnings-by-code-do-not-read-every-file",[764],{"type":45,"value":765},"Step 3: Triage warnings by code (do NOT read every file)",{"type":40,"tag":47,"props":767,"children":768},{},[769,771,776],{"type":45,"value":770},"Group the warnings from Step 2 by warning code and count them. ",{"type":40,"tag":68,"props":772,"children":773},{},[774],{"type":45,"value":775},"Do not open individual files yet.",{"type":45,"value":777}," Identify the top 1-2 patterns by count — these drive your fix strategy:",{"type":40,"tag":779,"props":780,"children":781},"table",{},[782,801],{"type":40,"tag":783,"props":784,"children":785},"thead",{},[786],{"type":40,"tag":787,"props":788,"children":789},"tr",{},[790,796],{"type":40,"tag":791,"props":792,"children":793},"th",{},[794],{"type":45,"value":795},"Pattern",{"type":40,"tag":791,"props":797,"children":798},{},[799],{"type":45,"value":800},"Typical fix",{"type":40,"tag":802,"props":803,"children":804},"tbody",{},[805,838,864],{"type":40,"tag":787,"props":806,"children":807},{},[808,820],{"type":40,"tag":809,"props":810,"children":811},"td",{},[812,814],{"type":45,"value":813},"Many IL2026 + IL3050 from ",{"type":40,"tag":162,"props":815,"children":817},{"className":816},[],[818],{"type":45,"value":819},"JsonSerializer",{"type":40,"tag":809,"props":821,"children":822},{},[823,828,830,836],{"type":40,"tag":68,"props":824,"children":825},{},[826],{"type":45,"value":827},"Go to Strategy C immediately",{"type":45,"value":829}," — create a ",{"type":40,"tag":162,"props":831,"children":833},{"className":832},[],[834],{"type":45,"value":835},"JsonSerializerContext",{"type":45,"value":837},", then batch-update all call sites",{"type":40,"tag":787,"props":839,"children":840},{},[841,853],{"type":40,"tag":809,"props":842,"children":843},{},[844,846,851],{"type":45,"value":845},"IL2070\u002FIL2087 on ",{"type":40,"tag":162,"props":847,"children":849},{"className":848},[],[850],{"type":45,"value":261},{"type":45,"value":852}," parameters",{"type":40,"tag":809,"props":854,"children":855},{},[856,857,862],{"type":45,"value":403},{"type":40,"tag":162,"props":858,"children":860},{"className":859},[],[861],{"type":45,"value":244},{"type":45,"value":863}," to the innermost method, then cascade outward",{"type":40,"tag":787,"props":865,"children":866},{},[867,877],{"type":40,"tag":809,"props":868,"children":869},{},[870,872],{"type":45,"value":871},"IL2067 passing unannotated ",{"type":40,"tag":162,"props":873,"children":875},{"className":874},[],[876],{"type":45,"value":261},{"type":40,"tag":809,"props":878,"children":879},{},[880],{"type":45,"value":881},"Annotate the parameter at the source",{"type":40,"tag":47,"props":883,"children":884},{},[885,890],{"type":40,"tag":68,"props":886,"children":887},{},[888],{"type":45,"value":889},"In most real projects, IL2026\u002FIL3050 from JsonSerializer dominate.",{"type":45,"value":891}," Start with Strategy C unless the warning breakdown clearly shows otherwise. After the batch JSON fix, handle remaining warnings with Strategies A–B. Only use Strategy D as a last resort.",{"type":40,"tag":177,"props":893,"children":895},{"id":894},"step-4-fix-warnings-iteratively-innermost-first",[896],{"type":45,"value":897},"Step 4: Fix warnings iteratively (innermost first)",{"type":40,"tag":47,"props":899,"children":900},{},[901,903,908],{"type":45,"value":902},"Work from the ",{"type":40,"tag":68,"props":904,"children":905},{},[906],{"type":45,"value":907},"innermost",{"type":45,"value":909}," reflection call outward. Each fix may cascade new warnings to callers.",{"type":40,"tag":47,"props":911,"children":912},{},[913,918],{"type":40,"tag":68,"props":914,"children":915},{},[916],{"type":45,"value":917},"Stay warning-driven.",{"type":45,"value":919}," For each warning, open only the file and line the compiler reported, identify the pattern, apply the matching fix recipe below, and move on. Do not scan the codebase for similar patterns or try to understand the full architecture — fix what the compiler tells you, rebuild, and let new warnings guide the next change. Fix a small batch of warnings (5-10), then rebuild immediately to check progress.",{"type":40,"tag":47,"props":921,"children":922},{},[923,928,930,936,938,943,945,950],{"type":40,"tag":68,"props":924,"children":925},{},[926],{"type":45,"value":927},"Use sub-agents when available.",{"type":45,"value":929}," If you can launch sub-agents (e.g., via a ",{"type":40,"tag":162,"props":931,"children":933},{"className":932},[],[934],{"type":45,"value":935},"task",{"type":45,"value":937}," tool), dispatch ",{"type":40,"tag":68,"props":939,"children":940},{},[941],{"type":45,"value":942},"multiple sub-agents in parallel",{"type":45,"value":944}," to edit different files simultaneously. Keep the main loop focused on building, parsing warnings, and dispatching — delegate actual file edits to sub-agents. For batch JSON updates, give each sub-agent 5-10 files to update in one prompt. ",{"type":40,"tag":68,"props":946,"children":947},{},[948],{"type":45,"value":949},"After 2 build-fix cycles, dispatch all remaining file edits to sub-agents in parallel — do not continue fixing files sequentially.",{"type":45,"value":951}," Example:",{"type":40,"tag":344,"props":953,"children":954},{},[955],{"type":40,"tag":47,"props":956,"children":957},{},[958,960,966,967,973,974,980,982,988,990,996,997,1003,1004,1010],{"type":45,"value":959},"Update these files to use source-generated JSON: ",{"type":40,"tag":162,"props":961,"children":963},{"className":962},[],[964],{"type":45,"value":965},"src\u002FModels\u002FResource.Serialization.cs",{"type":45,"value":376},{"type":40,"tag":162,"props":968,"children":970},{"className":969},[],[971],{"type":45,"value":972},"src\u002FModels\u002FIdentity.Serialization.cs",{"type":45,"value":376},{"type":40,"tag":162,"props":975,"children":977},{"className":976},[],[978],{"type":45,"value":979},"src\u002FModels\u002FPlan.Serialization.cs",{"type":45,"value":981},". In each file, replace ",{"type":40,"tag":162,"props":983,"children":985},{"className":984},[],[986],{"type":45,"value":987},"JsonSerializer.Serialize(writer, value)",{"type":45,"value":989}," with ",{"type":40,"tag":162,"props":991,"children":993},{"className":992},[],[994],{"type":45,"value":995},"JsonSerializer.Serialize(writer, value, MyProjectJsonContext.Default.TypeName)",{"type":45,"value":463},{"type":40,"tag":162,"props":998,"children":1000},{"className":999},[],[1001],{"type":45,"value":1002},"JsonSerializer.Deserialize\u003CT>(ref reader)",{"type":45,"value":989},{"type":40,"tag":162,"props":1005,"children":1007},{"className":1006},[],[1008],{"type":45,"value":1009},"JsonSerializer.Deserialize(ref reader, MyProjectJsonContext.Default.TypeName)",{"type":45,"value":1011},". Only edit the JsonSerializer call sites.",{"type":40,"tag":1013,"props":1014,"children":1016},"h4",{"id":1015},"strategy-a-add-dynamicallyaccessedmembers-preferred",[1017,1019,1024],{"type":45,"value":1018},"Strategy A: Add ",{"type":40,"tag":162,"props":1020,"children":1022},{"className":1021},[],[1023],{"type":45,"value":244},{"type":45,"value":1025}," (preferred)",{"type":40,"tag":47,"props":1027,"children":1028},{},[1029,1031,1036],{"type":45,"value":1030},"When a method uses reflection on a ",{"type":40,"tag":162,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":45,"value":261},{"type":45,"value":1037}," parameter, annotate the parameter to tell the trimmer what members are needed:",{"type":40,"tag":412,"props":1039,"children":1043},{"className":1040,"code":1041,"language":1042,"meta":417,"style":417},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","using System.Diagnostics.CodeAnalysis;\n\n\u002F\u002F Before (warns IL2070):\nvoid Process(Type t) {\n    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer can't verify\n}\n\n\u002F\u002F After (clean):\nvoid Process([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {\n    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer preserves public methods\n}\n","csharp",[1044],{"type":40,"tag":162,"props":1045,"children":1046},{"__ignoreMap":417},[1047,1055,1064,1072,1081,1090,1099,1107,1116,1125,1134],{"type":40,"tag":423,"props":1048,"children":1049},{"class":425,"line":426},[1050],{"type":40,"tag":423,"props":1051,"children":1052},{},[1053],{"type":45,"value":1054},"using System.Diagnostics.CodeAnalysis;\n",{"type":40,"tag":423,"props":1056,"children":1057},{"class":425,"line":435},[1058],{"type":40,"tag":423,"props":1059,"children":1061},{"emptyLinePlaceholder":1060},true,[1062],{"type":45,"value":1063},"\n",{"type":40,"tag":423,"props":1065,"children":1066},{"class":425,"line":444},[1067],{"type":40,"tag":423,"props":1068,"children":1069},{},[1070],{"type":45,"value":1071},"\u002F\u002F Before (warns IL2070):\n",{"type":40,"tag":423,"props":1073,"children":1075},{"class":425,"line":1074},4,[1076],{"type":40,"tag":423,"props":1077,"children":1078},{},[1079],{"type":45,"value":1080},"void Process(Type t) {\n",{"type":40,"tag":423,"props":1082,"children":1084},{"class":425,"line":1083},5,[1085],{"type":40,"tag":423,"props":1086,"children":1087},{},[1088],{"type":45,"value":1089},"    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer can't verify\n",{"type":40,"tag":423,"props":1091,"children":1093},{"class":425,"line":1092},6,[1094],{"type":40,"tag":423,"props":1095,"children":1096},{},[1097],{"type":45,"value":1098},"}\n",{"type":40,"tag":423,"props":1100,"children":1102},{"class":425,"line":1101},7,[1103],{"type":40,"tag":423,"props":1104,"children":1105},{"emptyLinePlaceholder":1060},[1106],{"type":45,"value":1063},{"type":40,"tag":423,"props":1108,"children":1110},{"class":425,"line":1109},8,[1111],{"type":40,"tag":423,"props":1112,"children":1113},{},[1114],{"type":45,"value":1115},"\u002F\u002F After (clean):\n",{"type":40,"tag":423,"props":1117,"children":1119},{"class":425,"line":1118},9,[1120],{"type":40,"tag":423,"props":1121,"children":1122},{},[1123],{"type":45,"value":1124},"void Process([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {\n",{"type":40,"tag":423,"props":1126,"children":1128},{"class":425,"line":1127},10,[1129],{"type":40,"tag":423,"props":1130,"children":1131},{},[1132],{"type":45,"value":1133},"    var method = t.GetMethod(\"Foo\");  \u002F\u002F trimmer preserves public methods\n",{"type":40,"tag":423,"props":1135,"children":1137},{"class":425,"line":1136},11,[1138],{"type":40,"tag":423,"props":1139,"children":1140},{},[1141],{"type":45,"value":1098},{"type":40,"tag":47,"props":1143,"children":1144},{},[1145,1147,1152,1154,1159,1161,1167,1169,1175],{"type":45,"value":1146},"When you annotate a parameter, ",{"type":40,"tag":68,"props":1148,"children":1149},{},[1150],{"type":45,"value":1151},"all callers",{"type":45,"value":1153}," must now pass properly annotated types. This cascades outward — follow each caller and annotate or refactor as needed. ",{"type":40,"tag":68,"props":1155,"children":1156},{},[1157],{"type":45,"value":1158},"The caller's annotation must include at least the same member types as the callee's.",{"type":45,"value":1160}," If the callee requires ",{"type":40,"tag":162,"props":1162,"children":1164},{"className":1163},[],[1165],{"type":45,"value":1166},"PublicConstructors | NonPublicConstructors",{"type":45,"value":1168},", the caller must specify the same or a superset — using only ",{"type":40,"tag":162,"props":1170,"children":1172},{"className":1171},[],[1173],{"type":45,"value":1174},"NonPublicConstructors",{"type":45,"value":1176}," will produce IL2091.",{"type":40,"tag":1013,"props":1178,"children":1180},{"id":1179},"strategy-b-refactor-to-preserve-annotation-flow",[1181],{"type":45,"value":1182},"Strategy B: Refactor to preserve annotation flow",{"type":40,"tag":47,"props":1184,"children":1185},{},[1186,1188,1193,1195,1200,1201,1206,1208,1213,1215,1220],{"type":45,"value":1187},"When annotation flow is broken by boxing (storing ",{"type":40,"tag":162,"props":1189,"children":1191},{"className":1190},[],[1192],{"type":45,"value":261},{"type":45,"value":1194}," in ",{"type":40,"tag":162,"props":1196,"children":1198},{"className":1197},[],[1199],{"type":45,"value":334},{"type":45,"value":376},{"type":40,"tag":162,"props":1202,"children":1204},{"className":1203},[],[1205],{"type":45,"value":269},{"type":45,"value":1207},", or untyped collections), ",{"type":40,"tag":68,"props":1209,"children":1210},{},[1211],{"type":45,"value":1212},"refactor",{"type":45,"value":1214}," to pass the ",{"type":40,"tag":162,"props":1216,"children":1218},{"className":1217},[],[1219],{"type":45,"value":261},{"type":45,"value":1221}," directly:",{"type":40,"tag":412,"props":1223,"children":1225},{"className":1040,"code":1224,"language":1042,"meta":417,"style":417},"\u002F\u002F BROKEN: Type boxed into object[], annotation lost\nvoid Process(object[] args) {\n    Type t = (Type)args[0];  \u002F\u002F IL2072: annotation lost through boxing\n    Evaluate(t, ...);\n}\n\n\u002F\u002F FIXED: Pass Type as a separate, annotated parameter\nvoid Process(\n    object[] args,\n    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type calleeType,\n    ...) {\n    Evaluate(calleeType, ...);  \u002F\u002F annotation flows cleanly\n}\n",[1226],{"type":40,"tag":162,"props":1227,"children":1228},{"__ignoreMap":417},[1229,1237,1245,1253,1261,1268,1275,1283,1291,1299,1307,1315,1324],{"type":40,"tag":423,"props":1230,"children":1231},{"class":425,"line":426},[1232],{"type":40,"tag":423,"props":1233,"children":1234},{},[1235],{"type":45,"value":1236},"\u002F\u002F BROKEN: Type boxed into object[], annotation lost\n",{"type":40,"tag":423,"props":1238,"children":1239},{"class":425,"line":435},[1240],{"type":40,"tag":423,"props":1241,"children":1242},{},[1243],{"type":45,"value":1244},"void Process(object[] args) {\n",{"type":40,"tag":423,"props":1246,"children":1247},{"class":425,"line":444},[1248],{"type":40,"tag":423,"props":1249,"children":1250},{},[1251],{"type":45,"value":1252},"    Type t = (Type)args[0];  \u002F\u002F IL2072: annotation lost through boxing\n",{"type":40,"tag":423,"props":1254,"children":1255},{"class":425,"line":1074},[1256],{"type":40,"tag":423,"props":1257,"children":1258},{},[1259],{"type":45,"value":1260},"    Evaluate(t, ...);\n",{"type":40,"tag":423,"props":1262,"children":1263},{"class":425,"line":1083},[1264],{"type":40,"tag":423,"props":1265,"children":1266},{},[1267],{"type":45,"value":1098},{"type":40,"tag":423,"props":1269,"children":1270},{"class":425,"line":1092},[1271],{"type":40,"tag":423,"props":1272,"children":1273},{"emptyLinePlaceholder":1060},[1274],{"type":45,"value":1063},{"type":40,"tag":423,"props":1276,"children":1277},{"class":425,"line":1101},[1278],{"type":40,"tag":423,"props":1279,"children":1280},{},[1281],{"type":45,"value":1282},"\u002F\u002F FIXED: Pass Type as a separate, annotated parameter\n",{"type":40,"tag":423,"props":1284,"children":1285},{"class":425,"line":1109},[1286],{"type":40,"tag":423,"props":1287,"children":1288},{},[1289],{"type":45,"value":1290},"void Process(\n",{"type":40,"tag":423,"props":1292,"children":1293},{"class":425,"line":1118},[1294],{"type":40,"tag":423,"props":1295,"children":1296},{},[1297],{"type":45,"value":1298},"    object[] args,\n",{"type":40,"tag":423,"props":1300,"children":1301},{"class":425,"line":1127},[1302],{"type":40,"tag":423,"props":1303,"children":1304},{},[1305],{"type":45,"value":1306},"    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type calleeType,\n",{"type":40,"tag":423,"props":1308,"children":1309},{"class":425,"line":1136},[1310],{"type":40,"tag":423,"props":1311,"children":1312},{},[1313],{"type":45,"value":1314},"    ...) {\n",{"type":40,"tag":423,"props":1316,"children":1318},{"class":425,"line":1317},12,[1319],{"type":40,"tag":423,"props":1320,"children":1321},{},[1322],{"type":45,"value":1323},"    Evaluate(calleeType, ...);  \u002F\u002F annotation flows cleanly\n",{"type":40,"tag":423,"props":1325,"children":1327},{"class":425,"line":1326},13,[1328],{"type":40,"tag":423,"props":1329,"children":1330},{},[1331],{"type":45,"value":1098},{"type":40,"tag":47,"props":1333,"children":1334},{},[1335],{"type":45,"value":1336},"Common patterns that break flow and how to fix them:",{"type":40,"tag":60,"props":1338,"children":1339},{},[1340,1362,1372,1382],{"type":40,"tag":64,"props":1341,"children":1342},{},[1343,1353,1355,1360],{"type":40,"tag":68,"props":1344,"children":1345},{},[1346,1351],{"type":40,"tag":162,"props":1347,"children":1349},{"className":1348},[],[1350],{"type":45,"value":269},{"type":45,"value":1352}," parameter bags",{"type":45,"value":1354},": Extract the ",{"type":40,"tag":162,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":45,"value":261},{"type":45,"value":1361}," into a dedicated annotated parameter",{"type":40,"tag":64,"props":1363,"children":1364},{},[1365,1370],{"type":40,"tag":68,"props":1366,"children":1367},{},[1368],{"type":45,"value":1369},"Dictionary\u002FList storage",{"type":45,"value":1371},": Use a typed field with annotation instead",{"type":40,"tag":64,"props":1373,"children":1374},{},[1375,1380],{"type":40,"tag":68,"props":1376,"children":1377},{},[1378],{"type":45,"value":1379},"Interface indirection",{"type":45,"value":1381},": Add annotation to the interface method's parameter",{"type":40,"tag":64,"props":1383,"children":1384},{},[1385,1390],{"type":40,"tag":68,"props":1386,"children":1387},{},[1388],{"type":45,"value":1389},"Property with boxing getter",{"type":45,"value":1391},": Annotate the property's return type",{"type":40,"tag":1013,"props":1393,"children":1395},{"id":1394},"strategy-c-source-generated-json-serialization-batch-fix",[1396],{"type":45,"value":1397},"Strategy C: Source-generated JSON serialization (batch fix)",{"type":40,"tag":47,"props":1399,"children":1400},{},[1401,1403,1409,1411,1417],{"type":45,"value":1402},"When most warnings are IL2026\u002FIL3050 from ",{"type":40,"tag":162,"props":1404,"children":1406},{"className":1405},[],[1407],{"type":45,"value":1408},"JsonSerializer.Serialize",{"type":45,"value":1410},"\u002F",{"type":40,"tag":162,"props":1412,"children":1414},{"className":1413},[],[1415],{"type":45,"value":1416},"Deserialize",{"type":45,"value":1418},", this is a single mechanical fix applied in bulk:",{"type":40,"tag":1420,"props":1421,"children":1422},"ol",{},[1423,1469],{"type":40,"tag":64,"props":1424,"children":1425},{},[1426,1431,1433,1438,1439,1445,1447,1453,1454,1460,1462,1468],{"type":40,"tag":68,"props":1427,"children":1428},{},[1429],{"type":45,"value":1430},"Collect affected types",{"type":45,"value":1432}," — grep for all ",{"type":40,"tag":162,"props":1434,"children":1436},{"className":1435},[],[1437],{"type":45,"value":1408},{"type":45,"value":463},{"type":40,"tag":162,"props":1440,"children":1442},{"className":1441},[],[1443],{"type":45,"value":1444},"JsonSerializer.Deserialize",{"type":45,"value":1446}," call sites. Extract the type being serialized (the ",{"type":40,"tag":162,"props":1448,"children":1450},{"className":1449},[],[1451],{"type":45,"value":1452},"\u003CT>",{"type":45,"value":1194},{"type":40,"tag":162,"props":1455,"children":1457},{"className":1456},[],[1458],{"type":45,"value":1459},"Deserialize\u003CT>",{"type":45,"value":1461},", or the runtime type of the object in ",{"type":40,"tag":162,"props":1463,"children":1465},{"className":1464},[],[1466],{"type":45,"value":1467},"Serialize",{"type":45,"value":271},{"type":40,"tag":64,"props":1470,"children":1471},{},[1472,1482,1483,1489,1491,1496,1498,1504,1506,1512],{"type":40,"tag":68,"props":1473,"children":1474},{},[1475,1477],{"type":45,"value":1476},"Create one ",{"type":40,"tag":162,"props":1478,"children":1480},{"className":1479},[],[1481],{"type":45,"value":835},{"type":45,"value":989},{"type":40,"tag":162,"props":1484,"children":1486},{"className":1485},[],[1487],{"type":45,"value":1488},"[JsonSerializable]",{"type":45,"value":1490}," for every type found. ",{"type":40,"tag":68,"props":1492,"children":1493},{},[1494],{"type":45,"value":1495},"Skip types from external packages",{"type":45,"value":1497}," (e.g., ",{"type":40,"tag":162,"props":1499,"children":1501},{"className":1500},[],[1502],{"type":45,"value":1503},"ResponseError",{"type":45,"value":1505}," from ",{"type":40,"tag":162,"props":1507,"children":1509},{"className":1508},[],[1510],{"type":45,"value":1511},"Azure.Core",{"type":45,"value":1513},") — they won't source-generate for types you don't own. Handle external types separately via Gotcha #1 below.",{"type":40,"tag":412,"props":1515,"children":1517},{"className":1040,"code":1516,"language":1042,"meta":417,"style":417},"[JsonSerializerContext]\n[JsonSerializable(typeof(ManagedServiceIdentity))]\n[JsonSerializable(typeof(SystemData))]\n\u002F\u002F ... one attribute per type YOU OWN\n\u002F\u002F Do NOT add types from external packages (e.g., ResponseError)\ninternal partial class MyProjectJsonContext : JsonSerializerContext { }\n",[1518],{"type":40,"tag":162,"props":1519,"children":1520},{"__ignoreMap":417},[1521,1529,1537,1545,1553,1561],{"type":40,"tag":423,"props":1522,"children":1523},{"class":425,"line":426},[1524],{"type":40,"tag":423,"props":1525,"children":1526},{},[1527],{"type":45,"value":1528},"[JsonSerializerContext]\n",{"type":40,"tag":423,"props":1530,"children":1531},{"class":425,"line":435},[1532],{"type":40,"tag":423,"props":1533,"children":1534},{},[1535],{"type":45,"value":1536},"[JsonSerializable(typeof(ManagedServiceIdentity))]\n",{"type":40,"tag":423,"props":1538,"children":1539},{"class":425,"line":444},[1540],{"type":40,"tag":423,"props":1541,"children":1542},{},[1543],{"type":45,"value":1544},"[JsonSerializable(typeof(SystemData))]\n",{"type":40,"tag":423,"props":1546,"children":1547},{"class":425,"line":1074},[1548],{"type":40,"tag":423,"props":1549,"children":1550},{},[1551],{"type":45,"value":1552},"\u002F\u002F ... one attribute per type YOU OWN\n",{"type":40,"tag":423,"props":1554,"children":1555},{"class":425,"line":1083},[1556],{"type":40,"tag":423,"props":1557,"children":1558},{},[1559],{"type":45,"value":1560},"\u002F\u002F Do NOT add types from external packages (e.g., ResponseError)\n",{"type":40,"tag":423,"props":1562,"children":1563},{"class":425,"line":1092},[1564],{"type":40,"tag":423,"props":1565,"children":1566},{},[1567],{"type":45,"value":1568},"internal partial class MyProjectJsonContext : JsonSerializerContext { }\n",{"type":40,"tag":1420,"props":1570,"children":1571},{"start":444},[1572,1725],{"type":40,"tag":64,"props":1573,"children":1574},{},[1575,1580,1582,1618,1622,1624,1689,1692,1694,1700,1702,1715,1717,1723],{"type":40,"tag":68,"props":1576,"children":1577},{},[1578],{"type":45,"value":1579},"Batch-update all call sites",{"type":45,"value":1581}," — do not read each file individually. Apply the pattern mechanically:",{"type":40,"tag":60,"props":1583,"children":1584},{},[1585,1602],{"type":40,"tag":64,"props":1586,"children":1587},{},[1588,1594,1596],{"type":40,"tag":162,"props":1589,"children":1591},{"className":1590},[],[1592],{"type":45,"value":1593},"JsonSerializer.Serialize(obj)",{"type":45,"value":1595}," → ",{"type":40,"tag":162,"props":1597,"children":1599},{"className":1598},[],[1600],{"type":45,"value":1601},"JsonSerializer.Serialize(obj, MyProjectJsonContext.Default.TypeName)",{"type":40,"tag":64,"props":1603,"children":1604},{},[1605,1611,1612],{"type":40,"tag":162,"props":1606,"children":1608},{"className":1607},[],[1609],{"type":45,"value":1610},"JsonSerializer.Deserialize\u003CT>(json)",{"type":45,"value":1595},{"type":40,"tag":162,"props":1613,"children":1615},{"className":1614},[],[1616],{"type":45,"value":1617},"JsonSerializer.Deserialize(json, MyProjectJsonContext.Default.TypeName)",{"type":40,"tag":1619,"props":1620,"children":1621},"br",{},[],{"type":45,"value":1623},"Find and update all call sites in one pass:",{"type":40,"tag":412,"props":1625,"children":1627},{"className":496,"code":1626,"language":498,"meta":417,"style":417},"# Find all files with JsonSerializer calls\ngrep -rl 'JsonSerializer\\.\\(Serialize\\|Deserialize\\)' src\u002F --include='*.cs'\n",[1628],{"type":40,"tag":162,"props":1629,"children":1630},{"__ignoreMap":417},[1631,1640],{"type":40,"tag":423,"props":1632,"children":1633},{"class":425,"line":426},[1634],{"type":40,"tag":423,"props":1635,"children":1637},{"style":1636},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[1638],{"type":45,"value":1639},"# Find all files with JsonSerializer calls\n",{"type":40,"tag":423,"props":1641,"children":1642},{"class":425,"line":435},[1643,1647,1652,1656,1661,1666,1671,1676,1680,1685],{"type":40,"tag":423,"props":1644,"children":1645},{"style":508},[1646],{"type":45,"value":390},{"type":40,"tag":423,"props":1648,"children":1649},{"style":513},[1650],{"type":45,"value":1651}," -rl",{"type":40,"tag":423,"props":1653,"children":1654},{"style":519},[1655],{"type":45,"value":586},{"type":40,"tag":423,"props":1657,"children":1658},{"style":513},[1659],{"type":45,"value":1660},"JsonSerializer\\.\\(Serialize\\|Deserialize\\)",{"type":40,"tag":423,"props":1662,"children":1663},{"style":519},[1664],{"type":45,"value":1665},"'",{"type":40,"tag":423,"props":1667,"children":1668},{"style":513},[1669],{"type":45,"value":1670}," src\u002F",{"type":40,"tag":423,"props":1672,"children":1673},{"style":513},[1674],{"type":45,"value":1675}," --include=",{"type":40,"tag":423,"props":1677,"children":1678},{"style":519},[1679],{"type":45,"value":1665},{"type":40,"tag":423,"props":1681,"children":1682},{"style":513},[1683],{"type":45,"value":1684},"*.cs",{"type":40,"tag":423,"props":1686,"children":1687},{"style":519},[1688],{"type":45,"value":596},{"type":40,"tag":1619,"props":1690,"children":1691},{},[],{"type":45,"value":1693},"Then use sequential ",{"type":40,"tag":162,"props":1695,"children":1697},{"className":1696},[],[1698],{"type":45,"value":1699},"edit",{"type":45,"value":1701}," calls to apply the same transformation to every matching file. ",{"type":40,"tag":68,"props":1703,"children":1704},{},[1705,1707,1713],{"type":45,"value":1706},"Do not use ",{"type":40,"tag":162,"props":1708,"children":1710},{"className":1709},[],[1711],{"type":45,"value":1712},"sed",{"type":45,"value":1714}," for C# code",{"type":45,"value":1716}," — generics like ",{"type":40,"tag":162,"props":1718,"children":1720},{"className":1719},[],[1721],{"type":45,"value":1722},"Deserialize\u003CT>()",{"type":45,"value":1724}," have angle brackets and nested parentheses that sed will mangle.",{"type":40,"tag":64,"props":1726,"children":1727},{},[1728,1733],{"type":40,"tag":68,"props":1729,"children":1730},{},[1731],{"type":45,"value":1732},"Build once",{"type":45,"value":1734}," to verify. Remaining warnings will be non-serialization issues — handle those with Strategies A–B or D.",{"type":40,"tag":1013,"props":1736,"children":1738},{"id":1737},"strategy-d-requiresunreferencedcode-last-resort",[1739,1741,1746],{"type":45,"value":1740},"Strategy D: ",{"type":40,"tag":162,"props":1742,"children":1744},{"className":1743},[],[1745],{"type":45,"value":286},{"type":45,"value":1747}," (last resort)",{"type":40,"tag":47,"props":1749,"children":1750},{},[1751],{"type":45,"value":1752},"When a method fundamentally requires arbitrary reflection that cannot be statically described:",{"type":40,"tag":412,"props":1754,"children":1756},{"className":1040,"code":1755,"language":1042,"meta":417,"style":417},"[RequiresUnreferencedCode(\"Loads plugins by name using Assembly.Load\")]\npublic void LoadPlugin(string assemblyName) {\n    var asm = Assembly.Load(assemblyName);\n    \u002F\u002F ...\n}\n",[1757],{"type":40,"tag":162,"props":1758,"children":1759},{"__ignoreMap":417},[1760,1768,1776,1784,1792],{"type":40,"tag":423,"props":1761,"children":1762},{"class":425,"line":426},[1763],{"type":40,"tag":423,"props":1764,"children":1765},{},[1766],{"type":45,"value":1767},"[RequiresUnreferencedCode(\"Loads plugins by name using Assembly.Load\")]\n",{"type":40,"tag":423,"props":1769,"children":1770},{"class":425,"line":435},[1771],{"type":40,"tag":423,"props":1772,"children":1773},{},[1774],{"type":45,"value":1775},"public void LoadPlugin(string assemblyName) {\n",{"type":40,"tag":423,"props":1777,"children":1778},{"class":425,"line":444},[1779],{"type":40,"tag":423,"props":1780,"children":1781},{},[1782],{"type":45,"value":1783},"    var asm = Assembly.Load(assemblyName);\n",{"type":40,"tag":423,"props":1785,"children":1786},{"class":425,"line":1074},[1787],{"type":40,"tag":423,"props":1788,"children":1789},{},[1790],{"type":45,"value":1791},"    \u002F\u002F ...\n",{"type":40,"tag":423,"props":1793,"children":1794},{"class":425,"line":1083},[1795],{"type":40,"tag":423,"props":1796,"children":1797},{},[1798],{"type":45,"value":1098},{"type":40,"tag":47,"props":1800,"children":1801},{},[1802,1804,1809],{"type":45,"value":1803},"This propagates to callers — they must also be annotated with ",{"type":40,"tag":162,"props":1805,"children":1807},{"className":1806},[],[1808],{"type":45,"value":286},{"type":45,"value":1810},". Use sparingly; it marks the entire call chain as trim-incompatible.",{"type":40,"tag":177,"props":1812,"children":1814},{"id":1813},"step-5-rebuild-and-repeat",[1815],{"type":45,"value":1816},"Step 5: Rebuild and repeat",{"type":40,"tag":47,"props":1818,"children":1819},{},[1820,1822,1828,1830,1835,1837,1843],{"type":45,"value":1821},"After each small batch of fixes (5-10 warnings), rebuild with ",{"type":40,"tag":162,"props":1823,"children":1825},{"className":1824},[],[1826],{"type":45,"value":1827},"--no-incremental",{"type":45,"value":1829}," and check for new warnings. ",{"type":40,"tag":68,"props":1831,"children":1832},{},[1833],{"type":45,"value":1834},"Do not attempt to fix all warnings before rebuilding",{"type":45,"value":1836}," — frequent rebuilds catch mistakes early and reveal cascading warnings. Fixes cascade — annotating an inner method may surface warnings in its callers. Repeat until ",{"type":40,"tag":162,"props":1838,"children":1840},{"className":1839},[],[1841],{"type":45,"value":1842},"0 Warning(s)",{"type":45,"value":1844},".",{"type":40,"tag":177,"props":1846,"children":1848},{"id":1847},"step-6-validate-all-tfms",[1849],{"type":45,"value":1850},"Step 6: Validate all TFMs",{"type":40,"tag":47,"props":1852,"children":1853},{},[1854],{"type":45,"value":1855},"Build all target frameworks to ensure:",{"type":40,"tag":60,"props":1857,"children":1858},{},[1859,1869,1886],{"type":40,"tag":64,"props":1860,"children":1861},{},[1862,1867],{"type":40,"tag":68,"props":1863,"children":1864},{},[1865],{"type":45,"value":1866},"0 IL warnings",{"type":45,"value":1868}," on net8.0+ TFMs",{"type":40,"tag":64,"props":1870,"children":1871},{},[1872,1877,1879,1884],{"type":40,"tag":68,"props":1873,"children":1874},{},[1875],{"type":45,"value":1876},"No NETSDK1210 warnings",{"type":45,"value":1878}," (the ",{"type":40,"tag":162,"props":1880,"children":1882},{"className":1881},[],[1883],{"type":45,"value":167},{"type":45,"value":1885}," condition handles this)",{"type":40,"tag":64,"props":1887,"children":1888},{},[1889,1894],{"type":40,"tag":68,"props":1890,"children":1891},{},[1892],{"type":45,"value":1893},"Clean builds",{"type":45,"value":1895}," on older TFMs (netstandard2.0, net472, etc.)",{"type":40,"tag":412,"props":1897,"children":1899},{"className":496,"code":1898,"language":498,"meta":417,"style":417},"dotnet build \u003Cproject.csproj>  # builds all TFMs\n",[1900],{"type":40,"tag":162,"props":1901,"children":1902},{"__ignoreMap":417},[1903],{"type":40,"tag":423,"props":1904,"children":1905},{"class":425,"line":426},[1906,1910,1914,1918,1922,1926,1930],{"type":40,"tag":423,"props":1907,"children":1908},{"style":508},[1909],{"type":45,"value":8},{"type":40,"tag":423,"props":1911,"children":1912},{"style":513},[1913],{"type":45,"value":516},{"type":40,"tag":423,"props":1915,"children":1916},{"style":519},[1917],{"type":45,"value":522},{"type":40,"tag":423,"props":1919,"children":1920},{"style":513},[1921],{"type":45,"value":527},{"type":40,"tag":423,"props":1923,"children":1924},{"style":530},[1925],{"type":45,"value":533},{"type":40,"tag":423,"props":1927,"children":1928},{"style":519},[1929],{"type":45,"value":538},{"type":40,"tag":423,"props":1931,"children":1932},{"style":1636},[1933],{"type":45,"value":1934},"  # builds all TFMs\n",{"type":40,"tag":53,"props":1936,"children":1938},{"id":1937},"stop-signals",[1939],{"type":45,"value":1940},"Stop Signals",{"type":40,"tag":60,"props":1942,"children":1943},{},[1944,1954,1964,1975,1987,2005,2017],{"type":40,"tag":64,"props":1945,"children":1946},{},[1947,1952],{"type":40,"tag":68,"props":1948,"children":1949},{},[1950],{"type":45,"value":1951},"Do not analyze more than 2-3 representative files per warning pattern.",{"type":45,"value":1953}," After identifying the fix for a pattern, apply it to all matching files without reading each one first.",{"type":40,"tag":64,"props":1955,"children":1956},{},[1957,1962],{"type":40,"tag":68,"props":1958,"children":1959},{},[1960],{"type":45,"value":1961},"Start fixing after one build.",{"type":45,"value":1963}," Do not do a second analysis pass — begin implementing fixes for the most common warning pattern immediately after Step 3 triage.",{"type":40,"tag":64,"props":1965,"children":1966},{},[1967,1969,1973],{"type":45,"value":1968},"Stop after achieving ",{"type":40,"tag":68,"props":1970,"children":1971},{},[1972],{"type":45,"value":1866},{"type":45,"value":1974}," for net8.0+ TFMs. Don't optimize or refactor already-clean annotations.",{"type":40,"tag":64,"props":1976,"children":1977},{},[1978,1980,1985],{"type":45,"value":1979},"If a warning requires ",{"type":40,"tag":68,"props":1981,"children":1982},{},[1983],{"type":45,"value":1984},"architectural refactoring",{"type":45,"value":1986}," beyond annotation flow fixes (e.g., replacing an entire serialization layer), document it and stop — don't rewrite large subsystems.",{"type":40,"tag":64,"props":1988,"children":1989},{},[1990,1992,1997,1999,2004],{"type":45,"value":1991},"Limit to ",{"type":40,"tag":68,"props":1993,"children":1994},{},[1995],{"type":45,"value":1996},"3 build-fix iterations",{"type":45,"value":1998}," per warning. If annotation flow doesn't resolve it after 3 attempts, escalate to ",{"type":40,"tag":162,"props":2000,"children":2002},{"className":2001},[],[2003],{"type":45,"value":286},{"type":45,"value":1844},{"type":40,"tag":64,"props":2006,"children":2007},{},[2008,2010,2015],{"type":45,"value":2009},"Don't chase warnings in ",{"type":40,"tag":68,"props":2011,"children":2012},{},[2013],{"type":45,"value":2014},"third-party dependencies",{"type":45,"value":2016}," you can't modify. Note them and move on.",{"type":40,"tag":64,"props":2018,"children":2019},{},[2020],{"type":45,"value":2021},"If the user asked a scoped question (e.g., \"fix warnings in this file\"), don't expand to the entire project.",{"type":40,"tag":53,"props":2023,"children":2025},{"id":2024},"polyfills-for-older-tfms",[2026],{"type":45,"value":2027},"Polyfills for Older TFMs",{"type":40,"tag":47,"props":2029,"children":2030},{},[2031,2033,2039,2041,2047],{"type":45,"value":2032},"For multi-targeting projects that include netstandard2.0 or net472, you need polyfills for ",{"type":40,"tag":162,"props":2034,"children":2036},{"className":2035},[],[2037],{"type":45,"value":2038},"DynamicallyAccessedMembersAttribute",{"type":45,"value":2040}," and related types. See ",{"type":40,"tag":2042,"props":2043,"children":2045},"a",{"href":2044},"references\u002Fpolyfills.md",[2046],{"type":45,"value":2044},{"type":45,"value":1844},{"type":40,"tag":53,"props":2049,"children":2051},{"id":2050},"common-gotchas",[2052],{"type":45,"value":2053},"Common Gotchas",{"type":40,"tag":1420,"props":2055,"children":2056},{},[2057],{"type":40,"tag":64,"props":2058,"children":2059},{},[2060,2065,2067,2072,2073,2078,2080,2086,2088,2094,2096,2101],{"type":40,"tag":68,"props":2061,"children":2062},{},[2063],{"type":45,"value":2064},"External types without AOT-safe serialization",{"type":45,"value":2066},": When a type comes from a dependency you can't modify (e.g., ",{"type":40,"tag":162,"props":2068,"children":2070},{"className":2069},[],[2071],{"type":45,"value":1503},{"type":45,"value":1505},{"type":40,"tag":162,"props":2074,"children":2076},{"className":2075},[],[2077],{"type":45,"value":1511},{"type":45,"value":2079},") and it lacks a source-generated serializer, ",{"type":40,"tag":162,"props":2081,"children":2083},{"className":2082},[],[2084],{"type":45,"value":2085},"Options.GetConverter\u003CT>()",{"type":45,"value":2087}," is reflection-based and will produce IL warnings. First check if the type implements ",{"type":40,"tag":162,"props":2089,"children":2091},{"className":2090},[],[2092],{"type":45,"value":2093},"IJsonModel\u003CT>",{"type":45,"value":2095}," (common in Azure SDK) — if so, bypass ",{"type":40,"tag":162,"props":2097,"children":2099},{"className":2098},[],[2100],{"type":45,"value":819},{"type":45,"value":2102}," entirely:",{"type":40,"tag":412,"props":2104,"children":2106},{"className":1040,"code":2105,"language":1042,"meta":417,"style":417},"\u002F\u002F Before (IL2026 — JsonSerializer uses reflection):\nJsonSerializer.Serialize(writer, errorValue);\n\n\u002F\u002F After (AOT-safe — uses IJsonModel directly):\n((IJsonModel\u003CResponseError>)errorValue).Write(writer, ModelReaderWriterOptions.Json);\n\n\u002F\u002F For deserialization:\nvar error = ((IJsonModel\u003CResponseError>)new ResponseError()).Create(ref reader, ModelReaderWriterOptions.Json);\n",[2107],{"type":40,"tag":162,"props":2108,"children":2109},{"__ignoreMap":417},[2110,2118,2126,2133,2141,2149,2156,2164],{"type":40,"tag":423,"props":2111,"children":2112},{"class":425,"line":426},[2113],{"type":40,"tag":423,"props":2114,"children":2115},{},[2116],{"type":45,"value":2117},"\u002F\u002F Before (IL2026 — JsonSerializer uses reflection):\n",{"type":40,"tag":423,"props":2119,"children":2120},{"class":425,"line":435},[2121],{"type":40,"tag":423,"props":2122,"children":2123},{},[2124],{"type":45,"value":2125},"JsonSerializer.Serialize(writer, errorValue);\n",{"type":40,"tag":423,"props":2127,"children":2128},{"class":425,"line":444},[2129],{"type":40,"tag":423,"props":2130,"children":2131},{"emptyLinePlaceholder":1060},[2132],{"type":45,"value":1063},{"type":40,"tag":423,"props":2134,"children":2135},{"class":425,"line":1074},[2136],{"type":40,"tag":423,"props":2137,"children":2138},{},[2139],{"type":45,"value":2140},"\u002F\u002F After (AOT-safe — uses IJsonModel directly):\n",{"type":40,"tag":423,"props":2142,"children":2143},{"class":425,"line":1083},[2144],{"type":40,"tag":423,"props":2145,"children":2146},{},[2147],{"type":45,"value":2148},"((IJsonModel\u003CResponseError>)errorValue).Write(writer, ModelReaderWriterOptions.Json);\n",{"type":40,"tag":423,"props":2150,"children":2151},{"class":425,"line":1092},[2152],{"type":40,"tag":423,"props":2153,"children":2154},{"emptyLinePlaceholder":1060},[2155],{"type":45,"value":1063},{"type":40,"tag":423,"props":2157,"children":2158},{"class":425,"line":1101},[2159],{"type":40,"tag":423,"props":2160,"children":2161},{},[2162],{"type":45,"value":2163},"\u002F\u002F For deserialization:\n",{"type":40,"tag":423,"props":2165,"children":2166},{"class":425,"line":1109},[2167],{"type":40,"tag":423,"props":2168,"children":2169},{},[2170],{"type":45,"value":2171},"var error = ((IJsonModel\u003CResponseError>)new ResponseError()).Create(ref reader, ModelReaderWriterOptions.Json);\n",{"type":40,"tag":47,"props":2173,"children":2174},{},[2175,2177,2182,2184,2189,2191,2196,2198,2204,2206,2212,2213,2219,2221,2227],{"type":45,"value":2176},"Do ",{"type":40,"tag":68,"props":2178,"children":2179},{},[2180],{"type":45,"value":2181},"not",{"type":45,"value":2183}," add the external type to your ",{"type":40,"tag":162,"props":2185,"children":2187},{"className":2186},[],[2188],{"type":45,"value":835},{"type":45,"value":2190}," — it won't source-generate for types you don't own. If the type doesn't implement ",{"type":40,"tag":162,"props":2192,"children":2194},{"className":2193},[],[2195],{"type":45,"value":2093},{"type":45,"value":2197},", write a custom ",{"type":40,"tag":162,"props":2199,"children":2201},{"className":2200},[],[2202],{"type":45,"value":2203},"JsonConverter\u003CT>",{"type":45,"value":2205}," with manual ",{"type":40,"tag":162,"props":2207,"children":2209},{"className":2208},[],[2210],{"type":45,"value":2211},"Utf8JsonReader",{"type":45,"value":1410},{"type":40,"tag":162,"props":2214,"children":2216},{"className":2215},[],[2217],{"type":45,"value":2218},"Utf8JsonWriter",{"type":45,"value":2220}," logic and register it via ",{"type":40,"tag":162,"props":2222,"children":2224},{"className":2223},[],[2225],{"type":45,"value":2226},"[JsonSourceGenerationOptions]",{"type":45,"value":2228}," on your context.",{"type":40,"tag":1420,"props":2230,"children":2231},{"start":435},[2232,2278],{"type":40,"tag":64,"props":2233,"children":2234},{},[2235,2240,2242,2248,2249,2255,2257,2263,2265,2270,2272,2277],{"type":40,"tag":68,"props":2236,"children":2237},{},[2238],{"type":45,"value":2239},"Serialization libraries",{"type":45,"value":2241},": Most reflection-based serializers (e.g., ",{"type":40,"tag":162,"props":2243,"children":2245},{"className":2244},[],[2246],{"type":45,"value":2247},"Newtonsoft.Json",{"type":45,"value":376},{"type":40,"tag":162,"props":2250,"children":2252},{"className":2251},[],[2253],{"type":45,"value":2254},"XmlSerializer",{"type":45,"value":2256},") are not AOT-compatible. Migrate to a source-generation-based serializer such as ",{"type":40,"tag":162,"props":2258,"children":2260},{"className":2259},[],[2261],{"type":45,"value":2262},"System.Text.Json",{"type":45,"value":2264}," with a ",{"type":40,"tag":162,"props":2266,"children":2268},{"className":2267},[],[2269],{"type":45,"value":835},{"type":45,"value":2271},". If migration is not feasible, mark the serialization call site with ",{"type":40,"tag":162,"props":2273,"children":2275},{"className":2274},[],[2276],{"type":45,"value":286},{"type":45,"value":1844},{"type":40,"tag":64,"props":2279,"children":2280},{},[2281,2286,2288,2294],{"type":40,"tag":68,"props":2282,"children":2283},{},[2284],{"type":45,"value":2285},"Shared projects \u002F projitems",{"type":45,"value":2287},": When source is shared between multiple projects via ",{"type":40,"tag":162,"props":2289,"children":2291},{"className":2290},[],[2292],{"type":45,"value":2293},"\u003CImport>",{"type":45,"value":2295},", annotations added to shared code affect ALL consuming projects. Verify that all consumers still build cleanly.",{"type":40,"tag":53,"props":2297,"children":2299},{"id":2298},"references",[2300],{"type":45,"value":2301},"References",{"type":40,"tag":47,"props":2303,"children":2304},{},[2305,2313,2320],{"type":40,"tag":2042,"props":2306,"children":2310},{"href":2307,"rel":2308},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Fnative-aot\u002F?tabs=windows%2Cnet8#limitations-of-native-aot-deployment",[2309],"nofollow",[2311],{"type":45,"value":2312},"Limitations",{"type":40,"tag":2042,"props":2314,"children":2317},{"href":2315,"rel":2316},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Ftrimming\u002Ftrimming-concepts",[2309],[2318],{"type":45,"value":2319},"Conceptual: Understanding trimming",{"type":40,"tag":2042,"props":2321,"children":2324},{"href":2322,"rel":2323},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fdotnet\u002Fcore\u002Fdeploying\u002Ftrimming\u002Ffixing-warnings",[2309],[2325],{"type":45,"value":2326},"How-to: trim compat",{"type":40,"tag":53,"props":2328,"children":2330},{"id":2329},"checklist",[2331],{"type":45,"value":2332},"Checklist",{"type":40,"tag":60,"props":2334,"children":2337},{"className":2335},[2336],"contains-task-list",[2338,2358,2367,2376,2398,2407,2416],{"type":40,"tag":64,"props":2339,"children":2342},{"className":2340},[2341],"task-list-item",[2343,2348,2350,2356],{"type":40,"tag":2344,"props":2345,"children":2347},"input",{"disabled":1060,"type":2346},"checkbox",[],{"type":45,"value":2349}," Added ",{"type":40,"tag":162,"props":2351,"children":2353},{"className":2352},[],[2354],{"type":45,"value":2355},"\u003CIsAotCompatible>",{"type":45,"value":2357}," with TFM condition to .csproj",{"type":40,"tag":64,"props":2359,"children":2361},{"className":2360},[2341],[2362,2365],{"type":40,"tag":2344,"props":2363,"children":2364},{"disabled":1060,"type":2346},[],{"type":45,"value":2366}," Built with AOT analyzers enabled (net8.0+ TFM)",{"type":40,"tag":64,"props":2368,"children":2370},{"className":2369},[2341],[2371,2374],{"type":40,"tag":2344,"props":2372,"children":2373},{"disabled":1060,"type":2346},[],{"type":45,"value":2375}," Fixed all IL warnings via annotations or refactoring",{"type":40,"tag":64,"props":2377,"children":2379},{"className":2378},[2341],[2380,2383,2385,2390,2391,2396],{"type":40,"tag":2344,"props":2381,"children":2382},{"disabled":1060,"type":2346},[],{"type":45,"value":2384}," No ",{"type":40,"tag":162,"props":2386,"children":2388},{"className":2387},[],[2389],{"type":45,"value":201},{"type":45,"value":82},{"type":40,"tag":162,"props":2392,"children":2394},{"className":2393},[],[2395],{"type":45,"value":217},{"type":45,"value":2397}," used for any IL warning",{"type":40,"tag":64,"props":2399,"children":2401},{"className":2400},[2341],[2402,2405],{"type":40,"tag":2344,"props":2403,"children":2404},{"disabled":1060,"type":2346},[],{"type":45,"value":2406}," Polyfills present for older TFMs if needed",{"type":40,"tag":64,"props":2408,"children":2410},{"className":2409},[2341],[2411,2414],{"type":40,"tag":2344,"props":2412,"children":2413},{"disabled":1060,"type":2346},[],{"type":45,"value":2415}," All target frameworks build with 0 warnings",{"type":40,"tag":64,"props":2417,"children":2419},{"className":2418},[2341],[2420,2423],{"type":40,"tag":2344,"props":2421,"children":2422},{"disabled":1060,"type":2346},[],{"type":45,"value":2424}," Verified shared\u002Flinked source doesn't break sibling projects",{"type":40,"tag":2426,"props":2427,"children":2428},"style",{},[2429],{"type":45,"value":2430},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2432,"total":2536},[2433,2448,2463,2481,2495,2514,2524],{"slug":2434,"name":2434,"fn":2435,"description":2436,"org":2437,"tags":2438,"stars":22,"repoUrl":23,"updatedAt":2447},"analyzing-dotnet-performance","analyze .NET code for performance anti-patterns","Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I\u002FO with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2439,2440,2443,2446],{"name":17,"slug":18,"type":15},{"name":2441,"slug":2442,"type":15},"Code Analysis","code-analysis",{"name":2444,"slug":2445,"type":15},"Debugging","debugging",{"name":13,"slug":14,"type":15},"2026-07-12T08:23:25.400375",{"slug":2449,"name":2449,"fn":2450,"description":2451,"org":2452,"tags":2453,"stars":22,"repoUrl":23,"updatedAt":2462},"android-tombstone-symbolication","symbolicate .NET runtime frames in Android tombstones","Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java\u002FKotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2454,2455,2458,2459],{"name":17,"slug":18,"type":15},{"name":2456,"slug":2457,"type":15},"Android","android",{"name":2444,"slug":2445,"type":15},{"name":2460,"slug":2461,"type":15},"Microsoft","microsoft","2026-07-12T08:23:21.595572",{"slug":2464,"name":2464,"fn":2465,"description":2466,"org":2467,"tags":2468,"stars":22,"repoUrl":23,"updatedAt":2480},"apple-crash-symbolication","symbolicate .NET runtime frames in crash logs","Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift\u002FObjective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2469,2470,2471,2474,2477],{"name":17,"slug":18,"type":15},{"name":2444,"slug":2445,"type":15},{"name":2472,"slug":2473,"type":15},"iOS","ios",{"name":2475,"slug":2476,"type":15},"macOS","macos",{"name":2478,"slug":2479,"type":15},"Observability","observability","2026-07-12T08:23:20.369986",{"slug":2482,"name":2482,"fn":2483,"description":2484,"org":2485,"tags":2486,"stars":22,"repoUrl":23,"updatedAt":2494},"assertion-quality","evaluate assertion quality in test suites","Analyzes the variety and depth of assertions across test suites in any language. Use when the user asks to evaluate assertion quality, find shallow tests, identify assertion-free tests (no assertions or only trivial ones like Assert.IsNotNull \u002F toBeTruthy()), flag self-referential or tautological assertions, measure assertion diversity, or audit whether tests verify different facets of behavior. Polyglot: .NET, Python, TS\u002FJS, Java, Go, Ruby, Rust, Swift, Kotlin, PowerShell, C++. DO NOT USE FOR: writing new tests (use code-testing-agent \u002F writing-mstest-tests), mutation reasoning about whether tests would catch a bug (use test-gap-analysis), or a general severity-ranked anti-pattern audit (use test-anti-patterns), fixing or rewriting assertions, or writing, fixing, or modernizing MSTest tests, assertions, or attributes (use writing-mstest-tests).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2487,2488,2491],{"name":2441,"slug":2442,"type":15},{"name":2489,"slug":2490,"type":15},"QA","qa",{"name":2492,"slug":2493,"type":15},"Testing","testing","2026-07-12T08:23:51.277743",{"slug":2496,"name":2496,"fn":2497,"description":2498,"org":2499,"tags":2500,"stars":22,"repoUrl":23,"updatedAt":2513},"author-component","create and review Blazor components","Create or review Blazor components (.razor files) with correct architecture. USE FOR: writing new Blazor components that do NOT involve JavaScript interop, implementing parameters and EventCallback, RenderFragment slots, component lifecycle (OnInitializedAsync, OnParametersSet), async patterns, IAsyncDisposable, CancellationToken, CSS isolation, code-behind. DO NOT USE FOR: creating new projects (use create-blazor-project), JavaScript interop or calling browser APIs from Blazor (use use-js-interop), forms and validation (use collect-user-input), prerendering issues (use support-prerendering), HTTP data fetching patterns (use fetch-and-send-data), coordinating state between unrelated components (use coordinate-components).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2501,2502,2505,2507,2510],{"name":17,"slug":18,"type":15},{"name":2503,"slug":2504,"type":15},"Blazor","blazor",{"name":2506,"slug":1042,"type":15},"C#",{"name":2508,"slug":2509,"type":15},"UI Components","ui-components",{"name":2511,"slug":2512,"type":15},"Web Development","web-development","2026-07-15T06:03:29.216359",{"slug":2515,"name":2515,"fn":2516,"description":2517,"org":2518,"tags":2519,"stars":22,"repoUrl":23,"updatedAt":2523},"binlog-failure-analysis","analyze MSBuild binary logs","Analyze MSBuild binary logs to diagnose build failures. USE FOR: build errors that are unclear from console output, diagnosing cascading failures across multi-project builds, tracing MSBuild target execution order, and generally any MSBuild build issues. Requires an existing .binlog file. DO NOT USE FOR: generating binlogs (use binlog-generation), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2520,2521,2522],{"name":2441,"slug":2442,"type":15},{"name":2444,"slug":2445,"type":15},{"name":2460,"slug":2461,"type":15},"2026-07-12T08:21:34.637923",{"slug":2525,"name":2525,"fn":2526,"description":2527,"org":2528,"tags":2529,"stars":22,"repoUrl":23,"updatedAt":2535},"binlog-generation","generate MSBuild binary logs for diagnostics","Generate MSBuild binary logs (binlogs) for build diagnostics and analysis. USE FOR: adding \u002Fbl:{} to any dotnet build, test, pack, publish, or restore command to capture a full build execution trace, prerequisite for binlog-failure-analysis and build-perf-diagnostics skills, enabling post-build investigation of errors or performance. Requires MSBuild 17.8+ \u002F .NET 8 SDK+ for {} placeholder; PowerShell needs -bl:{{}}. DO NOT USE FOR: non-MSBuild build systems (npm, Maven, CMake), analyzing an existing binlog (use binlog-failure-analysis instead).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2530,2533,2534],{"name":2531,"slug":2532,"type":15},"Build","build",{"name":2444,"slug":2445,"type":15},{"name":20,"slug":21,"type":15},"2026-07-19T05:38:19.340791",96,{"items":2538,"total":2643},[2539,2551,2558,2565,2573,2579,2587,2593,2599,2609,2622,2633],{"slug":2540,"name":2540,"fn":2541,"description":2542,"org":2543,"tags":2544,"stars":2548,"repoUrl":2549,"updatedAt":2550},"multithreaded-task-migration","migrate MSBuild tasks to multithreaded mode","Guide for migrating MSBuild tasks to multithreaded mode support, including compatibility red-team review. Use this when converting tasks to thread-safe versions, implementing IMultiThreadableTask, adding TaskEnvironment support, or auditing migrations for behavioral compatibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2545,2546,2547],{"name":17,"slug":18,"type":15},{"name":20,"slug":21,"type":15},{"name":13,"slug":14,"type":15},5535,"https:\u002F\u002Fgithub.com\u002Fdotnet\u002Fmsbuild","2026-07-22T05:37:33.965588",{"slug":2434,"name":2434,"fn":2435,"description":2436,"org":2552,"tags":2553,"stars":22,"repoUrl":23,"updatedAt":2447},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2554,2555,2556,2557],{"name":17,"slug":18,"type":15},{"name":2441,"slug":2442,"type":15},{"name":2444,"slug":2445,"type":15},{"name":13,"slug":14,"type":15},{"slug":2449,"name":2449,"fn":2450,"description":2451,"org":2559,"tags":2560,"stars":22,"repoUrl":23,"updatedAt":2462},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2561,2562,2563,2564],{"name":17,"slug":18,"type":15},{"name":2456,"slug":2457,"type":15},{"name":2444,"slug":2445,"type":15},{"name":2460,"slug":2461,"type":15},{"slug":2464,"name":2464,"fn":2465,"description":2466,"org":2566,"tags":2567,"stars":22,"repoUrl":23,"updatedAt":2480},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2568,2569,2570,2571,2572],{"name":17,"slug":18,"type":15},{"name":2444,"slug":2445,"type":15},{"name":2472,"slug":2473,"type":15},{"name":2475,"slug":2476,"type":15},{"name":2478,"slug":2479,"type":15},{"slug":2482,"name":2482,"fn":2483,"description":2484,"org":2574,"tags":2575,"stars":22,"repoUrl":23,"updatedAt":2494},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2576,2577,2578],{"name":2441,"slug":2442,"type":15},{"name":2489,"slug":2490,"type":15},{"name":2492,"slug":2493,"type":15},{"slug":2496,"name":2496,"fn":2497,"description":2498,"org":2580,"tags":2581,"stars":22,"repoUrl":23,"updatedAt":2513},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2582,2583,2584,2585,2586],{"name":17,"slug":18,"type":15},{"name":2503,"slug":2504,"type":15},{"name":2506,"slug":1042,"type":15},{"name":2508,"slug":2509,"type":15},{"name":2511,"slug":2512,"type":15},{"slug":2515,"name":2515,"fn":2516,"description":2517,"org":2588,"tags":2589,"stars":22,"repoUrl":23,"updatedAt":2523},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2590,2591,2592],{"name":2441,"slug":2442,"type":15},{"name":2444,"slug":2445,"type":15},{"name":2460,"slug":2461,"type":15},{"slug":2525,"name":2525,"fn":2526,"description":2527,"org":2594,"tags":2595,"stars":22,"repoUrl":23,"updatedAt":2535},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2596,2597,2598],{"name":2531,"slug":2532,"type":15},{"name":2444,"slug":2445,"type":15},{"name":20,"slug":21,"type":15},{"slug":2600,"name":2600,"fn":2601,"description":2602,"org":2603,"tags":2604,"stars":22,"repoUrl":23,"updatedAt":2608},"build-parallelism","optimize MSBuild build parallelism","Diagnose and fix under-parallelized MSBuild builds. USE WHEN a multi-project solution build is slower than expected, doesn't speed up when you add cores, pegs a single core while others idle, or you want to know why `-m` isn't helping. Note: `\u002Fmaxcpucount` default is 1 (sequential) — always pass `-m` for parallel builds. Covers finding the critical path (longest serial ProjectReference chain), graph build (`\u002Fgraph`), BuildInParallel, and solution filters (`.slnf`). DO NOT USE FOR: single-project builds, incremental issues (use incremental-build), compilation slowness inside one project (use build-perf-diagnostics), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2605,2606,2607],{"name":17,"slug":18,"type":15},{"name":20,"slug":21,"type":15},{"name":13,"slug":14,"type":15},"2026-07-19T05:38:18.364937",{"slug":2610,"name":2610,"fn":2611,"description":2612,"org":2613,"tags":2614,"stars":22,"repoUrl":23,"updatedAt":2621},"build-perf-baseline","establish and optimize build performance baselines","Establish build performance baselines and apply systematic optimization techniques. USE FOR: diagnosing slow builds, establishing before\u002Fafter measurements (cold, warm, no-op scenarios), applying optimization strategies like MSBuild Server, static graph builds, artifacts output, and dependency graph trimming. Start here before diving into build-perf-diagnostics, incremental-build, or build-parallelism. DO NOT USE FOR: non-MSBuild build systems, detailed bottleneck analysis (use build-perf-diagnostics after baselining).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2615,2616,2619,2620],{"name":20,"slug":21,"type":15},{"name":2617,"slug":2618,"type":15},"Monitoring","monitoring",{"name":13,"slug":14,"type":15},{"name":2492,"slug":2493,"type":15},"2026-07-12T08:21:35.865649",{"slug":2623,"name":2623,"fn":2624,"description":2625,"org":2626,"tags":2627,"stars":22,"repoUrl":23,"updatedAt":2632},"build-perf-diagnostics","diagnose MSBuild build performance bottlenecks","Diagnose MSBuild build performance bottlenecks using binary log analysis. USE FOR: identifying why builds are slow by analyzing binlog performance summaries, detecting ResolveAssemblyReference (RAR) taking >5s, Roslyn analyzers consuming >30% of Csc time, single targets dominating >50% of build time, node utilization below 80%, excessive Copy tasks, NuGet restore running every build. Covers timeline analysis, Target\u002FTask Performance Summary interpretation, and 7 common bottleneck categories. Use after build-perf-baseline has established measurements. DO NOT USE FOR: establishing initial baselines (use build-perf-baseline first), fixing incremental build issues (use incremental-build), parallelism tuning (use build-parallelism), non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2628,2629,2630,2631],{"name":17,"slug":18,"type":15},{"name":2444,"slug":2445,"type":15},{"name":20,"slug":21,"type":15},{"name":13,"slug":14,"type":15},"2026-07-12T08:21:40.961722",{"slug":2634,"name":2634,"fn":2635,"description":2636,"org":2637,"tags":2638,"stars":22,"repoUrl":23,"updatedAt":2642},"check-bin-obj-clash","detect MSBuild output path conflicts","Detects MSBuild projects with conflicting OutputPath or IntermediateOutputPath. USE FOR: builds failing with 'Cannot create a file when that file already exists', 'The process cannot access the file because it is being used by another process', intermittent build failures that succeed on retry, or missing\u002Foverwritten outputs in multi-project or multi-targeting builds where bin\u002Fobj (or project.assets.json) collide. Common causes: shared OutputPath, missing AppendTargetFrameworkToOutputPath, extra global properties (e.g. PublishReadyToRun), or SetTargetFramework on a ProjectReference to a single-targeting project. DO NOT USE FOR: file access errors unrelated to MSBuild (OS-level locking), single-project single-TFM builds, non-MSBuild build systems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2639,2640,2641],{"name":2444,"slug":2445,"type":15},{"name":20,"slug":21,"type":15},{"name":2489,"slug":2490,"type":15},"2026-07-19T05:38:14.336279",144]