C# 13 params collections: small but useful

Posted: (EET/GMT+2)

 

The next version of the C# language, version 13, includes a small but useful improvement to params parameters.

Before C# 13, params was normally tied to arrays. For instance:

public static void LogMessages(params string[] messages)
{
    foreach (string message in messages)
    {
        Console.WriteLine(message);
    }
}

This feature allows a convenient call syntax:

LogMessages("Starting", "Connecting", "Done");

In C# 13, params is being extended to work with more collection types, not only arrays.

For example, a method can use ReadOnlySpan<T>:

public static void LogMessages(params ReadOnlySpan<string> messages)
{
    foreach (string message in messages)
    {
        Console.WriteLine(message);
    }
}

The call site remains simple:

LogMessages("Starting", "Connecting", "Done");

This is useful because ReadOnlySpan<T> can avoid some allocations in hot code paths.

The same idea also works with other collection-style parameter types supported by collection expressions. For example:

public static void PrintNumbers(params List<int> numbers)
{
    foreach (int number in numbers)
    {
        Console.WriteLine(number);
    }
}

And the call still looks natural:

PrintNumbers(1, 2, 3, 4);

Tip: do not immediately change existing APIs only because this syntax exists. For normal application code, params string[] is still simple and familiar.

Good candidates for the new syntax are:

  • performance-sensitive helper methods
  • APIs that already use spans
  • library code where allocation behavior matters
  • methods that work naturally with collection expressions.

For most business applications, this is not a feature you need every day. But it is a nice quality-of-life improvement when writing reusable libraries or low-allocation helper code.

Also, keeping mind that if the method is public API, think carefully before changing from params T[] to another collection type. The source code may look similar, but API compatibility and overload resolution still matter.

At this point, C# 13 is still preview, so test this in a separate branch before using it in shared production code.

Hope this helps!