Delegate Allocation Traps in High-Throughput Pipelines
1Concept
Passing method groups (`list.Select(MyMethod)`) allocates a new delegate object on every call. Cache the delegate in a static field or use static lambda expressions to achieve zero allocations.
2Architecture Diagram
Method Group in Loop:
for (...) { Process(HelperMethod); } ──> Allocates `new Action()` on every iteration (GC Pressure!)
Cached Static Delegate:
private static readonly Action Cached = HelperMethod;
for (...) { Process(Cached); } ──> ZERO Allocations!3Code Example
C# 13 & .NET 9
using System;
public class DelegateCacheDemo
{
private static readonly Func<int, bool> CachedPredicate = static x => x > 0;
public static void Main()
{
int[] data = [-5, 10, -2, 30, 45];
// Zero-allocation filtering using cached delegate
int count = 0;
foreach (int item in data)
{
if (CachedPredicate(item)) count++;
}
Console.WriteLine($"Positive Items (Zero Allocation): {count}");
}
}4Expected Output
Positive Items (Zero Allocation): 3
5Key Takeaways
- ✓Avoid method group conversions in tight hot loops.
- ✓Use `static readonly` fields to cache reusable delegates.
- ✓Check heap allocations with `BenchmarkDotNet` [MemoryDiagnoser].