Ever used the params keyword in C#? If you write C# code regularly, you probably reach for it whenever you need to pass a variable number of arguments to a method. It’s super handy, letting you skip the tedious step of creating arrays first.

But until now, there’s been a limitation: params only worked with arrays. This meant every call created memory allocations with potential performance costs. The good news? C# 14 is changing the game by extending params to work with modern collections like IEnumerable<T>, Span<T>, and more.

How params Has Worked Until Now

Let’s look at how we’ve all been using params up to this point:

// Traditional params with arrays
public void DisplayNames(params string[] names)
{
    foreach (var name in names)
    {
        Console.WriteLine(name);
    }
}

// Usage
DisplayNames("Alice", "Bob", "Charlie");
// Behind the scenes: compiler creates a new string[] array

This pattern works, but brings some notable drawbacks:

  1. Each call allocates a new array on the heap (memory overhead)
  2. Frequent calls increase garbage collection pressure
  3. Arrays offer less flexibility than other collection types

The New params: Supporting Collections

C# 14 broadens the params keyword to work with various collection types:

  • IEnumerable<T>
  • ReadOnlySpan<T>
  • Span<T>
  • Other collection interfaces

Here’s what this looks like in real code:

// With IEnumerable<T>
public void ShowItems(params IEnumerable<string> items)
{
    foreach (var item in items)
    {
        Console.WriteLine(item);
    }
}

// With Span<T>
public void ProcessValues(params Span<int> values)
{
    for (int i = 0; i < values.Length; i++)
    {
        values[i] *= 2; // Can modify values with Span<T>
    }
}

Performance Implications

Let’s talk about the real-world performance benefits this change brings:

Reduced Allocations

With Span<T> or ReadOnlySpan<T>, you can skip heap allocations completely since these types can work with stack-allocated memory:

// No heap allocations needed
CalculateSum(params Span<int> values)
{
    int sum = 0;
    foreach (var value in values)
    {
        sum += value;
    }
    return sum;
}

var result = CalculateSum(1, 2, 3, 4, 5); // Uses the stack, not the heap

Better Fit with Modern APIs

Many newer .NET APIs use Span<T> for better performance. Now your code can fit right in with these patterns:

// Much cleaner than creating arrays just to pass them
public bool TryParseValues(params Span<char> characters)
{
    // Work directly with the span without extra memory use
    return ProcessSpanDirectly(characters);
}

Memory Usage: Before and After

Compare these two approaches:

// Old way
public void ProcessTraditional(params int[] values)
{
    // Process array values
}

// New way
public void ProcessModern(params ReadOnlySpan<int> values)
{
    // Process span values
}

// Old: Creates a new array on the heap
ProcessTraditional(1, 2, 3, 4, 5);

// New: No heap allocation needed
ProcessModern(1, 2, 3, 4, 5);

Cleaner LINQ Code

LINQ operations become more straightforward:

// Old way with array
public IEnumerable<T> CombineSources<T>(params IEnumerable<T>[] sources)
{
    return sources.SelectMany(source => source);
}

// New way, more direct
public IEnumerable<T> CombineSources<T>(params IEnumerable<T> sources)
{
    return sources.SelectMany(source => source);
}

About the Author

Abhinaw Kumar is a software engineer who builds real-world systems: from resilient ASP.NET Core backends to clean, maintainable Angular frontends. With over 11+ years in production development, he shares what actually works when you're shipping software that has to last.

Read more on the About page or connect on LinkedIn.

Frequently Asked Questions

What’s new about params in C# 14?

C# 14 extends the params keyword beyond arrays to support various collection types like IEnumerable, Span, ReadOnlySpan, and more. This means you can now create methods that accept a variable number of arguments without the mandatory array allocation overhead that existed in previous C# versions.

How does params for collections improve performance?

It reduces memory allocations by eliminating the need to create temporary arrays just to pass arguments. When using Span or ReadOnlySpan, the compiler can pass arguments directly without heap allocations, which is especially beneficial in high-performance scenarios or when processing large datasets.

Can I use params with any collection type?

No, there are restrictions. The collection type must be a valid params type, which includes arrays, IEnumerable, and span types. The collection must also be the last parameter in the method signature and can’t be used with ref, out, or in parameter modifiers.

Will my existing code with params arrays still work?

Yes, all existing code using params arrays will continue to work exactly as before. C# 14’s params extension is fully backward compatible. The new feature simply adds more options for defining params parameters with different collection types.

What’s the advantage of using params Span over params T[]?

Using params Span avoids heap allocations since spans operate on stack memory rather than the heap, making them more efficient, especially for methods called frequently. Spans also provide bounds checking and can represent segments of arrays or other memory without copying, which is perfect for high-performance computing.

Can I mix and match different collection types with params?

No, you can only specify one params parameter per method, and it must be the last parameter. However, you can overload methods to support different collection types if needed. Be aware this might lead to ambiguous method calls if the overloads aren’t carefully designed.

Related Posts