performance-reviewlisted
Install: claude install-skill Sarmkadan/dotnet-senior-skills
# Performance Review (.NET)
## First: does this code path earn optimization?
Optimize code that is (a) per-request or per-item in a hot loop, and (b) shown hot by a profiler or allocation trace - `dotnet-trace`, `dotnet-counters`, PerfView, or a BenchmarkDotNet micro-benchmark for the disputed snippet. Reject performance PRs justified by vibes, and equally reject "premature optimization" as an excuse for gratuitous waste in known-hot paths (serializers, middleware, per-row parsing). Startup code, admin endpoints, and once-a-day jobs get readability, not Spans.
The usual ranking of real wins: eliminate I/O (N+1, chatty HTTP, missing cache) >> reduce allocations >> micro-optimize CPU. A `Span<T>` refactor is noise next to an uncached per-request database call.
## Allocation review flags
- **Closures in hot paths**: a lambda capturing locals allocates a closure object per call. Use static lambdas with state parameters where the API offers them: `ConcurrentDictionary.GetOrAdd(key, static (k, arg) => Create(k, arg), arg)`.
- **LINQ in per-item loops**: each chained operator allocates an enumerator/iterator. `items.Where(...).Select(...).ToList()` once per request is fine; inside a loop over 100k rows, write the `foreach`. Also `Any()` on an `ICollection` - use `.Count > 0` (no enumerator).
- **params / interface enumeration**: `params object[]` allocates an array per call (logging!); `foreach` over `IEnumerable<T>` boxes the enumerator when the concrete type's is a struct - i