params Keyword in C#

The params keyword in C# allows a method to accept a variable number of arguments. Instead of forcing the caller to create an array manually, params lets the caller pass zero, one, or many values directly. Inside the method, those values are received as an array.

This is useful when a method naturally works with a list of values, such as adding numbers, formatting messages, logging items, joining strings, or passing multiple options. It makes method calls shorter and more flexible.


What Is params Keyword in C#?

params is used before the last parameter of a method. It tells the compiler that the caller can pass a variable number of arguments for that parameter.

int Add(params int[] numbers)
{
    int total = 0;

    foreach (int number in numbers)
    {
        total += number;
    }

    return total;
}

Console.WriteLine(Add(10, 20));
Console.WriteLine(Add(10, 20, 30, 40));

The method accepts any number of integer arguments. Inside the method, numbers behaves like an int[].

Syntax of params Keyword

returnType MethodName(params type[] parameterName)
{
    // method body
}

The params parameter must be an array type. The caller can pass individual values, an array, or no values at all.

Calling a params Method

A method with params can be called in multiple ways.

Add();
Add(5);
Add(5, 10, 15);
Add(new int[] { 1, 2, 3 });

All of these calls are valid. If no values are passed, the method receives an empty array, not null.

Rules of params Keyword

  • A method can have only one params parameter.
  • The params parameter must be the last parameter.
  • The params parameter must be an array.
  • Arguments passed to params must match the array element type.
  • The caller can pass individual values or an array.

These rules keep the call unambiguous. Since params collects the remaining arguments, it must appear at the end of the parameter list.

params with Regular Parameters

A method can have normal parameters before a params parameter. This is useful when the method needs one required value and then many optional extra values.

void Log(string level, params string[] messages)
{
    foreach (string message in messages)
    {
        Console.WriteLine($"[{level}] {message}");
    }
}

Log("INFO", "Started", "Connected", "Completed");

The first argument goes to level. The remaining arguments are collected into the messages array.

params with Strings

params is often used with strings when a method needs to combine or process multiple text values.

string JoinWords(params string[] words)
{
    return string.Join(" ", words);
}

Console.WriteLine(JoinWords("C#", "is", "powerful"));

The caller does not need to manually create a string array. The method call stays simple and readable.

params vs Array Parameter

FeatureparamsNormal Array Parameter
Caller can pass individual valuesYesNo
Caller can pass an arrayYesYes
Best forConvenient variable argumentsStrict array input
Method receivesArrayArray

Inside the method, both approaches use an array. The difference is mainly call-site convenience.

params vs Method Overloading

params can replace several overloads when the only difference is the number of repeated arguments.

int Add(int a, int b) => a + b;
int Add(int a, int b, int c) => a + b + c;

// Can be replaced by:
int AddAll(params int[] numbers) => numbers.Sum();

If the operation is the same for any number of values, params is often cleaner than many overloads.

params with Zero Arguments

A params method can be called without passing any values for the params parameter. In that case, the method receives an empty array. This is useful because the method can safely loop over the array without checking for null.

void PrintNumbers(params int[] numbers)
{
    Console.WriteLine($"Count: {numbers.Length}");
}

PrintNumbers();

This prints a count of 0. The method receives an empty array because no numbers were passed.

Passing an Existing Array to params

You can also pass an existing array to a params parameter. This is useful when the values are already stored in an array and do not need to be listed individually.

int[] values = { 2, 4, 6, 8 };

int total = Add(values);

The compiler does not create a nested array here. The existing array is passed as the params argument directly.

params object[] Example

Sometimes params object[] is used when a method must accept values of different types. This appears in formatting, logging, and older APIs. It is flexible, but it also reduces type safety because almost anything can be passed.

void LogValues(params object[] values)
{
    foreach (object value in values)
    {
        Console.WriteLine(value);
    }
}

LogValues("User", 25, true);

This works, but use it carefully. If the method expects specific types, strongly typed parameters or a custom model are usually safer.

params and Overload Resolution

If a method has both normal overloads and a params overload, the compiler usually prefers the more specific normal overload when it matches. The params overload is often used as a fallback for variable-length calls.

void Print(string message)
{
    Console.WriteLine("Single message");
}

void Print(params string[] messages)
{
    Console.WriteLine("Multiple messages");
}

Print("Hello");

The single-parameter overload is chosen because it is a better match. This is usually good, but too many overloads around params can make APIs harder to predict.

params with Generic Methods

params can be used with generic methods too. This keeps the method flexible while still preserving type safety.

void PrintItems<T>(params T[] items)
{
    foreach (T item in items)
    {
        Console.WriteLine(item);
    }
}

PrintItems(1, 2, 3);
PrintItems("A", "B", "C");

The compiler infers the type based on the arguments. The first call uses int, and the second call uses string.

Performance of params

When individual arguments are passed to a params method, the compiler creates an array to hold those values. For normal application code, this overhead is usually tiny. But in performance-critical code that runs millions of times, repeated array allocation can matter.

If performance is critical, measure first. In hot paths, a normal array, span-based API, or collection-based method may be more appropriate. For most business and learning code, params is chosen mainly for readability and convenience.

When Not to Use params

Do not use params when the method needs a structured set of different values. For example, a method that accepts name, email, age, status, and role should not use params object[]. A class, record, or normal parameter list would be clearer and safer.

params is best when all values have the same meaning and type, such as many numbers to add, many strings to join, or many messages to log.

params and API Design

A good params API should feel natural at the call site. The method name should make it obvious that multiple values are accepted. Names like AddAll, JoinWords, LogMessages, and PrintItems communicate variable-length input better than vague names.

If callers frequently pass arrays or lists rather than individual values, consider whether a collection parameter would be more honest. params is mostly a call-site convenience, not a replacement for proper collection design.

params with Empty and Null Arrays

When no values are passed to a params parameter, the method receives an empty array. However, a caller can still explicitly pass null if the parameter type allows it. This means defensive code may still be needed for public APIs.

void PrintAll(params string[] values)
{
    if (values == null)
    {
        return;
    }

    foreach (string value in values)
    {
        Console.WriteLine(value);
    }
}

In normal calls like PrintAll(), the array is empty. But explicit null input is still possible, so robust public methods should decide how they want to handle it.

params with Named Arguments

A params parameter can also be passed by name, but it must be supplied as an array. Named usage is less common because the main purpose of params is convenient positional variable arguments.

Log(level: "INFO", messages: new[] { "Started", "Completed" });

This is valid, but in most cases Log("INFO", "Started", "Completed") is cleaner. Named arguments are more useful for the regular parameters that come before params.

params and Collections

If the caller already has a List<T>, a params method may require converting it to an array. This is a sign that a collection-based overload may be useful when the API commonly receives existing collections.

List<int> values = new() { 1, 2, 3 };

int total = Add(values.ToArray());

If most callers already have lists, a method that accepts IEnumerable<int> may be more flexible. If most callers pass literal values, params is more convenient.

params Design Checklist

  • Do all values represent the same kind of input?
  • Is variable-length input natural for this method?
  • Would callers usually pass individual values?
  • Would an IEnumerable<T> parameter be more flexible?
  • Will overloads around this method stay unambiguous?

If the answer supports variable same-type values, params is a good fit. If the method needs structured data, use a model instead.

For readability, the params parameter name should usually be plural, such as numbers, messages, items, or values. A plural name tells the caller and reader that the method expects a group of values, not just one item.

Also keep the method body tolerant of empty input. Since callers can pass no values, the method should either handle an empty array naturally or document that at least one value is expected.

Common Mistakes with params Keyword

  • Trying to place another parameter after params.
  • Using more than one params parameter in the same method.
  • Using params when a normal collection would be clearer.
  • Assuming params accepts mixed unrelated types unless the array type allows it.
  • Creating confusing overloads alongside params.

Best Practices for params Keyword in C#

Use params when a method naturally accepts a variable number of values of the same type. Keep the method behavior simple, avoid mixing it with confusing overloads, and use normal collections when the caller is already working with lists or arrays.