params ReadOnlySpan: The Allocation-Free Params
Every time you call a method with params T[], the compiler sneaks in a brand-new array allocation behind your back. One call? No big deal. Thousands of calls on a hot path? You’re basically running a charity for the garbage collector. C# 13 finally lets you swap that T[] for ReadOnlySpan<T>, and the results are chef’s kiss.
The change is laughably simple. Just update your method signature:
// Before: every call allocates an arraypublic static int Sum(params int[] numbers){ var total = 0; foreach (var n in numbers) total += n; return total;}
// After: zero allocations, stack-allocated spanpublic static int Sum(params ReadOnlySpan<int> numbers){ var total = 0; foreach (var n in numbers) total += n; return total;}Callers don’t change at all. Sum(1, 2, 3) compiles exactly the same way. But under the hood, the compiler now stack-allocates the arguments into an inline array and wraps them in a ReadOnlySpan<T>. No heap. No GC pressure. No drama.
This shines anywhere you have variadic helpers that get called frequently: logging, formatting, math utilities, builder patterns, you name it. And because ReadOnlySpan<T> is a supertype of arrays anyway, existing callers that pass an explicit int[] still work. It’s a free upgrade.
// All of these just work:Sum(1, 2, 3); // inline span, zero allocSum([10, 20, 30]); // collection expression, zero allocSum(myArray); // existing array, still compilesThe takeaway? If you own a params method that lives anywhere near a hot path, slap ReadOnlySpan<T> on it and let the runtime do the rest. Your GC will send you a thank-you card.