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

输入参数

InputRequiredDescription
Source codeYesC# files, code blocks, or repository paths to scan
Hot-path contextRecommendedWhich code paths are performance-critical
Target frameworkRecommended.NET version (some patterns require .NET 8+)
Scan depthOptional
critical-only
,
standard
(default), or
comprehensive
输入必填描述
源代码待扫描的C#文件、代码块或仓库路径
热路径上下文推荐标注哪些代码路径是性能关键路径
目标框架推荐.NET版本(部分模式要求.NET 8+)
扫描深度可选
critical-only
standard
(默认)或
comprehensive

Workflow

工作流程

Step 1: Load Reference Files (if available)

步骤1:加载参考文件(若可用)

Try to load
references/critical-patterns.md
and the topic-specific reference files listed below. These contain detailed detection recipes and grep commands.
If 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.
尝试加载
references/critical-patterns.md
及下方列出的特定主题参考文件,这些文件包含详细的检测规则和grep命令。
如果未找到参考文件(例如在沙箱环境中,或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
## Detection
sections. Otherwise, use the inline recipes in Step 3.
Signal in CodeTopic
async
,
await
,
Task
,
ValueTask
Async patterns
Span<
,
Memory<
,
stackalloc
,
ArrayPool
,
string.Substring
,
.Replace(
,
.ToLower()
,
+=
in loops,
params 
Memory & strings
Regex
,
[GeneratedRegex]
,
Regex.Match
,
RegexOptions.Compiled
Regex patterns
Dictionary<
,
List<
,
.ToList()
,
.Where(
,
.Select(
, LINQ methods,
static readonly Dictionary<
Collections & LINQ
JsonSerializer
,
HttpClient
,
Stream
,
FileStream
I/O & serialization
Always check structural patterns (unsealed classes) regardless of signals.
Scan depth controls scope:
  • critical-only
    : Only critical patterns (deadlocks, >10x regressions)
  • standard
    (default): Critical + detected topic patterns
  • comprehensive
    : All pattern categories
扫描代码中的信号,确定需要检查的模式类别。如果已加载参考文件,使用其
## Detection
部分的规则,否则使用步骤3中的内嵌规则。
代码中的信号主题
async
await
Task
ValueTask
异步模式
Span<
Memory<
stackalloc
ArrayPool
string.Substring
.Replace(
.ToLower()
、循环中的
+=
params 
内存与字符串
Regex
[GeneratedRegex]
Regex.Match
RegexOptions.Compiled
正则表达式模式
Dictionary<
List<
.ToList()
.Where(
.Select(
、LINQ方法、
static readonly Dictionary<
集合与LINQ
JsonSerializer
HttpClient
Stream
FileStream
I/O与序列化
无论是否检测到对应信号,始终检查结构模式(非密封类)。
扫描深度控制范围:
  • critical-only
    :仅检测严重模式(死锁、10倍以上性能倒退)
  • 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确认命中数量,排查肉眼可能遗漏的模式。
对每个相关的模式类别,运行下方的检测规则,上报精确的命中数量,而非估算值。
核心扫描规则(无参考文件时运行这些规则):
undefined

Strings & 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:
  1. Branched
    .Replace()
    chains:
    Methods that call
    .Replace()
    across multiple
    if/else
    branches — report total allocation count across all branches, not just per-line.
  2. 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.
  3. Compound
    +=
    with embedded allocating calls:
    Lines like
    result += $"...{Foo().ToLower()}"
    are 2+ allocations (interpolation + ToLower + concatenation) — flag the compound cost, not just the
    .ToLower()
    .
  4. string.Format
    specificity:
    Distinguish resource-loaded format strings (not fixable) from compile-time literal format strings (fixable with interpolation). Enumerate the actionable sites.
运行完扫描规则后,查找单行规则无法检测到的多步骤分配模式:
  1. 分支式
    .Replace()
    调用链:
    跨多个
    if/else
    分支调用
    .Replace()
    的方法 — 上报所有分支的总分配次数,而非单行统计。
  2. 跨方法调用链: 某个公共方法委托给另一个本身会分配中间变量的方法(例如A调用B,B执行3次正则替换,然后A调用C),将整个调用链的总开销作为一个结果上报。
  3. 内嵌分配调用的复合
    +=
    操作:
    类似
    result += $"...{Foo().ToLower()}"
    的代码行存在2次以上分配(插值+ToLower+拼接) — 标记复合开销,而非仅标记
    .ToLower()
  4. string.Format
    特异性:
    区分资源加载的格式字符串(无法修复)和编译时常量格式字符串(可用插值修复),枚举可操作的位点。

Step 4: Classify and Prioritize Findings

步骤4:结果分类与优先级排序

Assign each finding a severity:
SeverityCriteriaAction
🔴 CriticalDeadlocks, crashes, security vulnerabilities, >10x regressionMust fix
🟡 Moderate2-10x improvement opportunity, best practice for hot pathsShould fix on hot paths
ℹ️ InfoPattern applies but code may not be on a hot pathConsider if profiling shows impact
Prioritization rules:
  1. If the user identified hot-path code, elevate all findings in that code to their maximum severity
  2. 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"
  3. 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. 如果用户标注了热路径代码,将该代码内的所有结果提升到最高严重等级
  2. 如果热路径上下文未知,无条件上报🔴严重结果;上报🟡中等结果时备注:「若该代码处于热路径则影响较大」
  3. 永远不要对明显非性能敏感的代码建议微优化
规模导向的严重等级升级: 当同一模式在大量实例中出现时,提升严重等级:
  • 同一反模式出现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
保持结果简洁。 每个结果为一个短块,不要写成长篇大论。按严重等级分组(🔴 → 🟡 → ℹ️),而非按文件分组。
每个结果的格式:
undefined

ID. 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
StringComparison.Ordinal
parameter") Caveat: only if non-obvious (version requirement, correctness risk)

**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

常见误区

PitfallCorrect Approach
Flagging every
Dictionary
as needing
FrozenDictionary
Only flag if the dictionary is never mutated after construction
Suggesting
Span<T>
in async methods
Use
Memory<T>
in async code;
Span<T>
only in sync hot paths
Reporting LINQ outside hot pathsOnly 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
ConfigureAwait(false)
in app code
Only applicable in library code; not primarily a performance concern
Recommending
ValueTask
everywhere
Only for hot paths with frequent synchronous completion
Flagging
new HttpClient()
in DI services
Check if
IHttpClientFactory
is already in use
Suggesting
[GeneratedRegex]
for dynamic patterns
Only flag when the pattern string is a compile-time literal
Suggesting
CollectionsMarshal.AsSpan
broadly
Only for ultra-hot paths with benchmarked evidence; adds complexity and fragility
Suggesting
unsafe
code for micro-optimizations
Avoid
unsafe
except where absolutely necessary — do not recommend it for micro-optimizations that don't matter. Safe alternatives like
Span<T>
,
stackalloc
in safe context, and
ArrayPool
cover the vast majority of performance needs
误区正确做法
将所有
Dictionary
标记为需要改为
FrozenDictionary
仅当字典构造后永远不会被修改时才标记
在异步方法中建议使用
Span<T>
异步代码中使用
Memory<T>
Span<T>
仅适用于同步热路径
上报热路径外的LINQ问题仅标记已确认热路径或紧循环中的LINQ;运行频率低的代码中使用LINQ是可接受的。从.NET 7开始,LINQ的Min/Max/Sum/Average已向量化,全面禁止LINQ是错误的
在应用代码中建议使用
ConfigureAwait(false)
该方法仅适用于库代码,且不是主要的性能优化点
建议所有地方都使用
ValueTask
仅适用于频繁同步完成的热路径
标记DI服务中的
new HttpClient()
检查是否已经在使用
IHttpClientFactory
建议动态模式使用
[GeneratedRegex]
仅当模式字符串是编译时常量时才标记
大范围建议使用
CollectionsMarshal.AsSpan
仅用于有基准测试证据的超热路径;该方法会增加复杂度和脆弱性
建议用
unsafe
代码做微优化
除非绝对必要,否则避免使用
unsafe
— 不要为无关紧要的微优化推荐它。
Span<T>
、安全上下文下的
stackalloc
ArrayPool
等安全替代方案可以满足绝大多数性能需求