[c#] Why use the params keyword?

I know this is a basic question, but I couldn't find an answer.

Why use it? if you write a function or a method that's using it, when you remove it the code will still work perfectly, 100% as without it. E.g:

With params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

Without params:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}

This question is related to c# parameter-passing params variadic-functions variadic

The answer is


No need to create overload methods, just use one single method with params as shown below

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);

Using params allows you to call the function with no arguments. Without params:

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

Compare with params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

Generally, you can use params when the number of arguments can vary from 0 to infinity, and use an array when numbers of arguments vary from 1 to infinity.


Adding params keyword itself shows that you can pass multiple number of parameters while calling that method which is not possible without using it. To be more specific:

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

When you will call above method you can call it by any of the following ways:

  1. addTwoEach()
  2. addTwoEach(1)
  3. addTwoEach(new int[]{ 1, 2, 3, 4 })

But when you will remove params keyword only third way of the above given ways will work fine. For 1st and 2nd case you will get an error.


One more important thing needs to be highlighted. It's better to use params because it is better for performance. When you call a method with params argument and passed to it nothing:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

call:

ExampleMethod();

Then a new versions of the .Net Framework do this (from .Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

This Array.Empty object can be reused by framework later, so there are no needs to do redundant allocations. These allocations will occur when you call this method like this:

 ExampleMethod(new string[] {});

params also allows you to call the method with a single argument.

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

i.e. Foo(1); instead of Foo(new int[] { 1 });. Can be useful for shorthand in scenarios where you might need to pass in a single value rather than an entire array. It still is handled the same way in the method, but gives some candy for calling this way.


Might sound stupid, But Params doesn't allow multidimensional array. Whereas you can pass a multidimensional array to a function.


It allows you to add as many base type parameters in your call as you like.

addTwoEach(10, 2, 4, 6)

whereas with the second form you have to use an array as parameter

addTwoEach(new int[] {10,2,4,6})

One danger with params Keyword is, if after Calls to the Method have been coded,

  1. someone accidentally / intentionally removes one/more required Parameters from the Method Signature, and
  2. one/more required Parameters immediately prior to the params Parameter prior to the Signature change were Type-Compatible with the params Parameter,

those Calls will continue to compile with one/more Expressions previously intended for required Parameters being treated as the optional params Parameter. I just ran into the worst possible case of this: the params Parameter was of Type object[].

This is noteworthy because developers are used to the compiler slapping their wrists with the much, much more common scenario where Parameters are removed from a Method with all required Parameters (because the # of Parameters expected would change).

For me, it's not worth the shortcut. (Type)[] without params will work with 0 to infinity # of Parameters without needing Overrides. Worst case is you'll have to add a , new (Type) [] {} to Calls where it doesn't apply.

Btw, imho, the safest (and most readable practice) is to:

  1. pass via Named Parameters (which we can now do even in C# ~2 decades after we could in VB ;P) (because:

    1.1. it's the only way that guarantees prevention of unintended values passed to Parameters after Parameter order, Compatible-Type and/or count change after Calls have been coded,

    1.2. it reduces those chances after a Parameter meaning change, because the likely new identifier name reflecting the new meaning is right next to the value being passed to it,

    1.3. it avoids having to count commas and jump back & forth from Call to Signature to see what Expression is being passed for what Parameter, and

    1.3.1. By the way, this reason alone should be plenty (in terms of avoiding frequent error-prone violations of the DRY Principle just to read the code not to mention also modify it), but this reason can be exponentially more important if there are one/more Expressions being Passed that themselves contain commas, i.e. Multi-Dimensional Array Refs or Multi-Parameter Function Calls. In that case, you couldn't even use (which even if you could, would still be adding an extra step per Parameter per Method Call) a Find All Occurrences in a Selection feature in your editor to automate the comma-counting for you.

    1.4. if you must use Optional Parameters (params or not), it allows you to search for Calls where a particular Optional Parameter is Passed (and therefore, most likely is not or at least has the possibility of being not the Default Value),

(NOTE: Reasons 1.2. and 1.3. can ease and reduce chances of error even on coding the initial Calls not to mention when Calls have to be read and/or changed.))

and

  1. do so ONE - PARAMETER - PER - LINE for better readability (because:

    2.1. it's less cluttered, and

    2.2. it avoids having to scroll right & back left (and having to do so PER - LINE, since most mortals can't read the left part of multiple lines, scroll right and read the right part)).

    2.3. it's consistent with the "Best Practice" we've already evolved into for Assignment Statements, because every Parameter Passed is in essence an Assignment Statement (assigning a Value or Reference to a Local Variable). Just like those who follow the latest "Best Practice" in Coding Style wouldn't dream of coding multiple Assignment Statements per line, we probably shouldn't (and won't once "Best Practice" catches up to my "genius" ;P ) do so when Passing Parameters.

NOTES:

  1. Passing in Variables whose names mirror the Parameters' doesn't help when:

    1.1. you're passing in Literal Constants (i.e. a simple 0/1, false/true or null that even "'Best Practices'" may not require you use a Named Constant for and their purpose can't be easily inferred from the Method name),

    1.2. the Method is significantly lower-level / more generic than the Caller such that you would not want / be able to name your Variables the same/similar to the Parameters (or vice versa), or

    1.3. you're re-ordering / replacing Parameters in the Signature that may result in prior Calls still Compiling because the Types happen to still be compatible.

  2. Having an auto-wrap feature like VS does only eliminates ONE (#2.2) of the 8 reasons I gave above. Prior to as late as VS 2015, it did NOT auto-indent (!?! Really, MS?!?) which increases severity of reason #2.1.

VS should have an option that generates Method Call snippets with Named Parameters (one per line of course ;P) and a compiler option that requires Named Parameters (similar in concept to Option Explicit in VB which, btw, the requirement of was prolly once thought equally as outrageous but now is prolly required by "'Best Practices'"). In fact, "back in my day" ;), in 1991 just months into my career, even before I was using (or had even seen) a language with Named Parameters, I had the anti-sheeple / "just cuz you can, don't mean you should" / don't blindly "cut the ends of the roast" sense enough to simulate it (using in-line comments) without having seen anyone do so. Not having to use Named Parameters (as well other syntax that save "'precious'" source code keystrokes) is a relic of the Punch Card era when most of these syntaxes started. There's no excuse for that with modern hardware and IDE's and much more complex software where readability is much, Much, MUCH more important. "Code is read much more often than is written". As long as you're not duplicating non-auto-updated code, every keystroke saved is likely to cost exponentially more when someone (even yourself) is trying to read it later.


Another example

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

var items = Tokenize(product.Name, product.FullName, product.Xyz)

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to parameter-passing

How to pass parameter to a promise function Check number of arguments passed to a Bash script How to pass event as argument to an inline event handler in JavaScript? Passing Parameters JavaFX FXML Invoke a second script with arguments from a script How can I pass a member function where a free function is expected? Passing variables, creating instances, self, The mechanics and usage of classes: need explanation In Javascript/jQuery what does (e) mean? How to write a bash script that takes optional input arguments? Passing Objects By Reference or Value in C#

Examples related to params

How to pass parameters to $http in angularjs? Why use the params keyword? Android set height and width of Custom view programmatically

Examples related to variadic-functions

Concatenate two slices in Go Possible heap pollution via varargs parameter How to pass an ArrayList to a varargs method parameter? Why use the params keyword? What do 3 dots next to a parameter type mean in Java? Can I pass an array as arguments to a method with variable arguments in Java? Java variable number or arguments for a method Is it possible to send a variable number of arguments to a JavaScript function? Variable number of arguments in C++? How to pass variable number of arguments to a PHP function

Examples related to variadic

Why use the params keyword? How to make a variadic macro (variable number of arguments)