> **See also:** for pattern-by-pattern detection recipes with measured impact numbers and ❌/✅ pairs, see the topic catalogs: [critical-patterns.md](critical-patterns.md), [async-patterns.md](async-patterns.md), [memory-and-strings.md](memory-and-strings.md), [collections-and-linq.md](collections-and-linq.md), [regex-patterns.md](regex-patterns.md), [io-and-serialization.md](io-and-serialization.md), [structural-patterns.md](structural-patterns.md). This file covers the conceptual framing (when/why), those files cover the catalog (what/how-much).
Use this reference after a profile or benchmark identifies a hot path. Do not apply these patterns speculatively.
## Table Of Contents
- [LINQ And Enumeration](#linq-and-enumeration)
- [Stack Allocation, Span, And Memory](#stack-allocation-span-and-memory)
- [Structs, Boxing, And Copies](#structs-boxing-and-copies)
- [Buffer Reuse And Advanced Helpers](#buffer-reuse-and-advanced-helpers)
- [Strings](#strings)
- [What Not To Suggest](#what-not-to-suggest)
## LINQ And Enumeration
### Property or indexer over LINQ when the concrete collection is known
Wrong:
```csharp
if (items.Count() > 0)
{
return items.First();
}
```
Better:
```csharp
if (items.Count > 0)
{
return items[0];
}
```
Use `Count`, `Length`, `IsEmpty`, or an indexer when you already have a concrete collection with that API. Relevant analyzers: `CA1826`, `CA1829`, `CA1836`, `CA1860`.
### `Any()` over `Count() > 0` when all you know is `IEnumerable<T>`
Wrong:
```csharp
if (source.Count() != 0)
{
Process(source);
}
```
Better:
```csharp
if (source.Any())
{
Process(source);
}
```
Relevant analyzer: `CA1827`.
### Avoid multiple enumeration of deferred queries
Wrong:
```csharp
var query = source.Where(Filter);
return query.Count() + query.Last().Id;
```
Better:
```csharp
var materialized = source.Where(Filter).ToArray();
return materialized.Length + materialized[^1].Id;
```
Materialize once only when you truly need multiple passes or random access and can afford the extra memory. Relevant analyzer: `CA1851`.
### Avoid premature materialization
Wrong:
```csharp
var projected = source.ToList().Select(Map);
```
Better:
```csharp
var projected = source.Select(Map);
```
Keep deferred execution unless you need a snapshot, repeated traversal, indexing, or a boundary between expensive stages.
- .NET 10 improved many LINQ operations substantially through JIT array-interface devirtualisation — operations like `Skip`/`Take`/`Sum` on arrays and `ReadOnlyCollection<T>` got roughly 50% faster *for free*. See Stephen Toub, [Performance Improvements in .NET 10](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-10/).
- On `net8.0` LINQ has the historical performance characteristics described in [Performance Improvements in .NET 8](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/) — fast paths exist for `Count`, `ToList`, `ToArray` on `ICollection<T>`, but indexed access via `ElementAt`/`Skip`/`Take` is not as cheap as on .NET 10.