analyzing-dotnet-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese.NET Performance Patterns
.NET性能模式
Scan C#/.NET code for performance anti-patterns and produce prioritized findings with concrete fixes. Patterns sourced from the official .NET performance blog series, distilled to customer-actionable guidance.
扫描C#/.NET代码中的性能反模式,输出带具体修复方案的优先级结果。模式来源为官方.NET性能博客系列,已提炼为可供用户落地的指导建议。
When to Use
适用场景
- Reviewing C#/.NET code for performance optimization opportunities
- Auditing hot paths for allocation-heavy or inefficient patterns
- Systematic scan of a codebase for known anti-patterns before release
- Second-opinion analysis after manual performance review
- 审查C#/.NET代码的性能优化机会
- 审计热路径中的高内存分配或低效模式
- 发布前对代码库的已知反模式进行系统性扫描
- 手动性能审查后的二次分析校验
When Not to Use
不适用场景
- Algorithmic complexity analysis — this skill targets API usage patterns, not algorithm design
- Code not on a hot path with no performance requirements — avoid premature optimization
- 算法复杂度分析 — 本技能针对API使用模式,而非算法设计
- 无性能要求的非热路径代码 — 避免过早优化
Inputs
输入参数
| Input | Required | Description |
|---|---|---|
| Source code | Yes | C# files, code blocks, or repository paths to scan |
| Hot-path context | Recommended | Which code paths are performance-critical |
| Target framework | Recommended | .NET version (some patterns require .NET 8+) |
| Scan depth | Optional | |
| 输入 | 必填 | 描述 |
|---|---|---|
| 源代码 | 是 | 待扫描的C#文件、代码块或仓库路径 |
| 热路径上下文 | 推荐 | 标注哪些代码路径是性能关键路径 |
| 目标框架 | 推荐 | .NET版本(部分模式要求.NET 8+) |
| 扫描深度 | 可选 | |
Workflow
工作流程
Step 1: Load Reference Files (if available)
步骤1:加载参考文件(若可用)
Try to load and the topic-specific reference files listed below. These contain detailed detection recipes and grep commands.
references/critical-patterns.mdIf reference files are not found (e.g., in a sandboxed environment or when the skill is embedded as instructions only), skip file loading and proceed directly to Step 3 using the scan recipes listed inline below. Do not spend time searching the filesystem for reference files — if they aren't at the expected relative path, they aren't available.
尝试加载及下方列出的特定主题参考文件,这些文件包含详细的检测规则和grep命令。
references/critical-patterns.md如果未找到参考文件(例如在沙箱环境中,或skill仅作为指令嵌入时),跳过文件加载,直接使用下方内嵌的扫描规则进入步骤3。不要花费时间在文件系统中搜索参考文件,如果它们不在预期的相对路径下,即表示不可用。
Step 2: Detect Code Signals and Select Topic Recipes
步骤2:检测代码信号并选择主题规则
Scan the code for signals that indicate which pattern categories to check. If reference files were loaded, use their sections. Otherwise, use the inline recipes in Step 3.
## Detection| Signal in Code | Topic |
|---|---|
| Async patterns |
| Memory & strings |
| Regex patterns |
| Collections & LINQ |
| I/O & serialization |
Always check structural patterns (unsealed classes) regardless of signals.
Scan depth controls scope:
- : Only critical patterns (deadlocks, >10x regressions)
critical-only - (default): Critical + detected topic patterns
standard - : All pattern categories
comprehensive
扫描代码中的信号,确定需要检查的模式类别。如果已加载参考文件,使用其部分的规则,否则使用步骤3中的内嵌规则。
## Detection| 代码中的信号 | 主题 |
|---|---|
| 异步模式 |
| 内存与字符串 |
| 正则表达式模式 |
| 集合与LINQ |
| I/O与序列化 |
无论是否检测到对应信号,始终检查结构模式(非密封类)。
扫描深度控制范围:
- :仅检测严重模式(死锁、10倍以上性能倒退)
critical-only - (默认):严重模式 + 检测到的对应主题模式
standard - :所有模式类别
comprehensive
Step 3: Scan and Report
步骤3:扫描并上报结果
For files under 500 lines, read the entire file first — you'll spot most patterns faster than running individual grep recipes. Use grep to confirm counts and catch patterns you might miss visually.
For each relevant pattern category, run the detection recipes below. Report exact counts, not estimates.
Core scan recipes (run these when reference files aren't available):
undefined对于500行以下的文件,先通读全文件 — 相比单独运行grep规则,你可以更快发现大部分模式,再用grep确认命中数量,排查肉眼可能遗漏的模式。
对每个相关的模式类别,运行下方的检测规则,上报精确的命中数量,而非估算值。
核心扫描规则(无参考文件时运行这些规则):
undefinedStrings & memory
Strings & memory
grep -n '.IndexOf("' FILE # Missing StringComparison
grep -n '.Substring(' FILE # Substring allocations
grep -En '.(StartsWith|EndsWith|Contains)\s*(' FILE # Missing StringComparison
grep -n '.ToLower()|.ToUpper()' FILE # Culture-sensitive + allocation
grep -n '.Replace(' FILE # Chained Replace allocations
grep -n 'params ' FILE # params array allocation
grep -n '.IndexOf("' FILE # Missing StringComparison
grep -n '.Substring(' FILE # Substring allocations
grep -En '.(StartsWith|EndsWith|Contains)\s*(' FILE # Missing StringComparison
grep -n '.ToLower()|.ToUpper()' FILE # Culture-sensitive + allocation
grep -n '.Replace(' FILE # Chained Replace allocations
grep -n 'params ' FILE # params array allocation
Collections & LINQ
Collections & LINQ
grep -n '.Select|.Where|.OrderBy|.GroupBy' FILE # LINQ on hot path
grep -n '.All|.Any' FILE # LINQ on string/char
grep -n 'new Dictionary<|new List<' FILE # Per-call allocation
grep -n 'static readonly Dictionary<' FILE # FrozenDictionary candidate
grep -n '.Select|.Where|.OrderBy|.GroupBy' FILE # LINQ on hot path
grep -n '.All|.Any' FILE # LINQ on string/char
grep -n 'new Dictionary<|new List<' FILE # Per-call allocation
grep -n 'static readonly Dictionary<' FILE # FrozenDictionary candidate
Regex
Regex
grep -n 'RegexOptions.Compiled' FILE # Compiled regex budget
grep -n 'new Regex(' FILE # Per-call regex
grep -n 'GeneratedRegex' FILE # Positive: source-gen regex
grep -n 'RegexOptions.Compiled' FILE # Compiled regex budget
grep -n 'new Regex(' FILE # Per-call regex
grep -n 'GeneratedRegex' FILE # Positive: source-gen regex
Structural
Structural
grep -n 'public class |internal class ' FILE # Unsealed classes
grep -n 'sealed class' FILE # Already sealed
grep -n ': IEquatable' FILE # Positive: struct equality
**Rules:**
- Run every relevant recipe for the detected pattern categories
- **Emit a scan execution checklist** before classifying findings — list each recipe and the hit count
- A result of **0 hits** is valid and valuable (confirms good practice)
- If reference files were loaded, also run their `## Detection` recipes
**Verify-the-Inverse Rule:** For absence patterns, always count both sides and report the ratio (e.g., "N of M classes are sealed"). The ratio determines severity — 0/185 is systematic, 12/15 is a consistency fix.grep -n 'public class |internal class ' FILE # Unsealed classes
grep -n 'sealed class' FILE # Already sealed
grep -n ': IEquatable' FILE # Positive: struct equality
**规则:**
- 对检测到的模式类别运行所有相关规则
- 对结果分类前**输出扫描执行清单** — 列出每个规则及命中数量
- **0命中**是有效且有价值的结果(证明代码符合最佳实践)
- 如果已加载参考文件,同时运行其`## Detection`部分的规则
**反向验证规则:** 针对缺失类模式,始终统计正反两面的数量并上报比例(例如「M个类中有N个是密封类」)。比例决定严重程度 — 0/185属于系统性问题,12/15属于一致性修复问题。Step 3b: Cross-File Consistency Check
步骤3b:跨文件一致性检查
If an optimized pattern is found in one file, check whether sibling files (same directory, same interface, same base class) use the un-optimized equivalent. Flag as 🟡 Moderate with the optimized file as evidence.
如果在某个文件中发现优化后的模式,检查同级文件(同目录、同接口、同基类)是否使用了未优化的等效实现,标记为🟡中等严重,将优化后的文件作为证据。
Step 3c: Compound Allocation Check
步骤3c:复合内存分配检查
After running scan recipes, look for these multi-allocation patterns that single-line recipes miss:
- Branched chains: Methods that call
.Replace()across multiple.Replace()branches — report total allocation count across all branches, not just per-line.if/else - Cross-method chaining: When a public method delegates to another method that itself allocates intermediates (e.g., A calls B which does 3 regex replaces, then A calls C), report the total chain cost as one finding.
- Compound with embedded allocating calls: Lines like
+=are 2+ allocations (interpolation + ToLower + concatenation) — flag the compound cost, not just theresult += $"...{Foo().ToLower()}"..ToLower() - specificity: Distinguish resource-loaded format strings (not fixable) from compile-time literal format strings (fixable with interpolation). Enumerate the actionable sites.
string.Format
运行完扫描规则后,查找单行规则无法检测到的多步骤分配模式:
- 分支式调用链: 跨多个
.Replace()分支调用if/else的方法 — 上报所有分支的总分配次数,而非单行统计。.Replace() - 跨方法调用链: 某个公共方法委托给另一个本身会分配中间变量的方法(例如A调用B,B执行3次正则替换,然后A调用C),将整个调用链的总开销作为一个结果上报。
- 内嵌分配调用的复合操作: 类似
+=的代码行存在2次以上分配(插值+ToLower+拼接) — 标记复合开销,而非仅标记result += $"...{Foo().ToLower()}"。.ToLower() - 特异性: 区分资源加载的格式字符串(无法修复)和编译时常量格式字符串(可用插值修复),枚举可操作的位点。
string.Format
Step 4: Classify and Prioritize Findings
步骤4:结果分类与优先级排序
Assign each finding a severity:
| Severity | Criteria | Action |
|---|---|---|
| 🔴 Critical | Deadlocks, crashes, security vulnerabilities, >10x regression | Must fix |
| 🟡 Moderate | 2-10x improvement opportunity, best practice for hot paths | Should fix on hot paths |
| ℹ️ Info | Pattern applies but code may not be on a hot path | Consider if profiling shows impact |
Prioritization rules:
- If the user identified hot-path code, elevate all findings in that code to their maximum severity
- If hot-path context is unknown, report 🔴 Critical findings unconditionally; report 🟡 Moderate findings with a note: "Impactful if this code is on a hot path"
- Never suggest micro-optimizations on code that is clearly not performance-sensitive
Scale-based severity escalation:
When the same pattern appears across many instances, escalate severity:
- 1-10 instances of the same anti-pattern → report at the pattern's base severity
- 11-50 instances → escalate ℹ️ Info patterns to 🟡 Moderate
- 50+ instances → escalate to 🟡 Moderate with elevated priority; flag as a codebase-wide systematic issue
Always report exact counts (from scan recipes), not estimates or agent summaries.
为每个结果分配严重等级:
| 严重等级 | 判定标准 | 处理建议 |
|---|---|---|
| 🔴 严重 | 死锁、崩溃、安全漏洞、10倍以上性能倒退 | 必须修复 |
| 🟡 中等 | 2-10倍性能提升空间、热路径最佳实践 | 热路径上应当修复 |
| ℹ️ 提示 | 模式匹配但代码可能不在热路径上 | 若性能分析显示有影响可考虑修复 |
优先级规则:
- 如果用户标注了热路径代码,将该代码内的所有结果提升到最高严重等级
- 如果热路径上下文未知,无条件上报🔴严重结果;上报🟡中等结果时备注:「若该代码处于热路径则影响较大」
- 永远不要对明显非性能敏感的代码建议微优化
规模导向的严重等级升级:
当同一模式在大量实例中出现时,提升严重等级:
- 同一反模式出现1-10例 → 按模式的基础严重等级上报
- 出现11-50例 → 将ℹ️提示模式升级为🟡中等
- 出现50例以上 → 升级为🟡中等并提升优先级,标记为全代码库系统性问题
始终上报(来自扫描规则的)精确数量,而非估算值或Agent总结。
Step 5: Generate Findings
步骤5:生成结果
Keep findings compact. Each finding is one short block — not an essay. Group by severity (🔴 → 🟡 → ℹ️), not by file.
Format per finding:
undefined保持结果简洁。 每个结果为一个短块,不要写成长篇大论。按严重等级分组(🔴 → 🟡 → ℹ️),而非按文件分组。
每个结果的格式:
undefinedID. Title (N instances)
ID. 标题 (N个实例)
Impact: one-line impact statement
Files: file1.cs:L1, file2.cs:L2, ... (list locations, don't build tables)
Fix: one-line description of the change (e.g., "Add parameter")
Caveat: only if non-obvious (version requirement, correctness risk)
StringComparison.Ordinal
**Rules for compact output:**
- **No ❌/✅ code blocks** for trivial fixes (adding a keyword, parameter, or type change). A one-line fix description suffices.
- **Only include code blocks** for non-obvious transformations (e.g., replacing a LINQ chain with a foreach loop, or hoisting a closure).
- **File locations as inline comma-separated list**, not a table. Use `File.cs:L42` format.
- **No explanatory prose** beyond the Impact line — the severity icon already conveys urgency.
- **Merge related findings** that share the same fix (e.g., all `.ToLower()` calls go in one finding, not split by file).
- **Positive findings** in a bullet list, not a table. One line per pattern: `✅ Pattern — evidence`.
End with a summary table and disclaimer:
```markdown
| Severity | Count | Top Issue |
|----------|-------|-----------|
| 🔴 Critical | N | ... |
| 🟡 Moderate | N | ... |
| ℹ️ Info | N | ... |
> ⚠️ **Disclaimer:** These results are generated by an AI assistant and are non-deterministic. Findings may include false positives, miss real issues, or suggest changes that are incorrect for your specific context. Always verify recommendations with benchmarks and human review before applying changes to production code.影响: 单行影响说明
文件: file1.cs:L1, file2.cs:L2, ...(列出位置,不要建表格)
修复方案: 变更的单行描述(例如「添加参数」)
注意事项: 仅当不直观时填写(版本要求、正确性风险)
StringComparison.Ordinal
**简洁输出规则:**
- trivial修复(添加关键字、参数或类型变更)**不需要❌/✅代码块**,单行修复说明即可。
- **仅当转换逻辑不直观时才包含代码块**(例如将LINQ链替换为foreach循环,或提升闭包)。
- **文件位置用逗号分隔的行内列表**,不要用表格,使用`File.cs:L42`格式。
- 除了影响说明外**不要额外的解释性文字**,严重等级图标已经传达了紧急程度。
- **合并相同修复方案的相关结果**(例如所有`.ToLower()`调用归为一个结果,不要按文件拆分)。
- **正向结果用无序列表**,不要用表格,每个模式占一行:`✅ 模式 — 证据`。
末尾添加汇总表格和免责声明:
```markdown
| 严重等级 | 数量 | 首要问题 |
|----------|-------|-----------|
| 🔴 严重 | N | ... |
| 🟡 中等 | N | ... |
| ℹ️ 提示 | N | ... |
> ⚠️ **免责声明:** 这些结果由AI助手生成,不具备确定性。结果可能包含误报、遗漏真实问题,或给出不适合您特定上下文的错误修改建议。在应用到生产代码前,请务必通过基准测试和人工审核验证所有建议。Validation
校验
Before delivering results, verify:
- All critical patterns were checked (from reference files or inline recipes)
- Topic-specific recipes run only when matching signals detected
- Each finding includes a concrete code fix
- Scan execution checklist is complete (all recipes run)
- Summary table included at end
交付结果前,确认:
- 所有严重模式都已检查(来自参考文件或内嵌规则)
- 仅当检测到匹配信号时才运行特定主题规则
- 每个结果都包含具体的代码修复方案
- 扫描执行清单完整(所有规则都已运行)
- 末尾包含汇总表格
Common Pitfalls
常见误区
| Pitfall | Correct Approach |
|---|---|
Flagging every | Only flag if the dictionary is never mutated after construction |
Suggesting | Use |
| Reporting LINQ outside hot paths | Only flag LINQ in identified hot paths or tight loops; LINQ is acceptable in code that runs infrequently. Since .NET 7, LINQ Min/Max/Sum/Average are vectorized — blanket bans on LINQ are misguided |
Suggesting | Only applicable in library code; not primarily a performance concern |
Recommending | Only for hot paths with frequent synchronous completion |
Flagging | Check if |
Suggesting | Only flag when the pattern string is a compile-time literal |
Suggesting | Only for ultra-hot paths with benchmarked evidence; adds complexity and fragility |
Suggesting | Avoid |
| 误区 | 正确做法 |
|---|---|
将所有 | 仅当字典构造后永远不会被修改时才标记 |
在异步方法中建议使用 | 异步代码中使用 |
| 上报热路径外的LINQ问题 | 仅标记已确认热路径或紧循环中的LINQ;运行频率低的代码中使用LINQ是可接受的。从.NET 7开始,LINQ的Min/Max/Sum/Average已向量化,全面禁止LINQ是错误的 |
在应用代码中建议使用 | 该方法仅适用于库代码,且不是主要的性能优化点 |
建议所有地方都使用 | 仅适用于频繁同步完成的热路径 |
标记DI服务中的 | 检查是否已经在使用 |
建议动态模式使用 | 仅当模式字符串是编译时常量时才标记 |
大范围建议使用 | 仅用于有基准测试证据的超热路径;该方法会增加复杂度和脆弱性 |
建议用 | 除非绝对必要,否则避免使用 |