361

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;
}
MasterMastic
  • 20,711
  • 12
  • 68
  • 90
  • 66
    The code of the method itself will still work perfectly... the *calling* code may well not... – Jon Skeet Sep 28 '11 at 08:30
  • 7
    params key word means OPTIONAL parameters that can be passed or not to the Method. An array with out params key word means you MUST pass array argument to the method. – Ailayna Entarria May 05 '14 at 09:24
  • Python language implements the same concept so sweetly with an asterisk(`*`) prefixed parameter as mentioned [here](https://docs.python.org/3/tutorial/controlflow.html#keyword-arguments). – RBT Jul 28 '18 at 00:11

11 Answers11

517

With params you can call your method like this:

addTwoEach(1, 2, 3, 4, 5);

Without params, you can’t.

Additionally, you can call the method with an array as a parameter in both cases:

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

That is, params allows you to use a shortcut when calling the method.

Unrelated, you can drastically shorten your method:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 18
    @Ken: You might need to import the `System.Linq` namespace :) – Ranhiru Jude Cooray Sep 28 '11 at 08:31
  • 55
    Or return args.Sum(i => i + 2); – bornfromanegg Feb 19 '15 at 11:44
  • 3
    The sum with a delegate, though, does increase the complexity of the compiled code, which could potentially be less performant. Not really relevant in this particular situation, as it would not result in any closures, but it's worth knowing what the compiler's actually doing to make the best choice. – Allen Clark Copeland Jr Nov 28 '15 at 22:15
  • 2
    You could also use `return args.Select(x => x + 2).Sum();` – bbvg Aug 22 '17 at 21:07
  • Didn't know C# had an equivalent for Python's `*args`! Love it. Note: If the method has multiple parameters, the `params` parameter must be the last one in the list. – Emil Feb 06 '19 at 18:05
  • 1
    When you add `params` you *lock* yourself out of adding additional method arguments without breaking your callers or method resolution. – Mr. Young Dec 03 '19 at 00:09
103

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.

Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
Tadeusz
  • 6,453
  • 9
  • 40
  • 58
22

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})
okrumnow
  • 2,346
  • 23
  • 39
21

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.2.

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.

Tom
  • 870
  • 11
  • 13
  • 2
    I don't understand. Why can't you just enforce that there be at least one? Even without params there's nothing to stop you from passing `null` or `new object[0]` as the argument. – Casey Oct 28 '15 at 13:38
  • It's probably just too dangerous to ever have required parameters prior to the optional one (in case one or more of those required ones are removed after calls are coded). That may be why I've never seen required parameters before the the optional parameter in sample code in any docs on optional parameters. Btw, imho, the safest (and most readable practice) is to pass via named parameters (which we can now do *even* in C# ~2 decades after we could in VB). VS should have an option that generates method call snippets with named parameters (and do so 1 parameter per line). – Tom Mar 07 '17 at 02:41
  • I'm not really sure what you mean. The only way you can have required parameters and optional ones is to specify all the required ones first. – Casey Mar 08 '17 at 03:55
  • 1
    Ex. I declare `myMethod` as `void myMethod(int requiredInt, params int[] optionalInts)`. I / someone else codes one/more calls, i.e. `myMethod(1)`, `myMethod(1, 21)`, `myMethod(1, 21, 22)`. I change `myMethod` to be `void myMethod(params int[] optionalInts)`. All those calls will still compile with no errors even though their 1st parameters (the "1"'s) were clearly not intended to be passed as the 1st element of the `optionalInts` Parameter. – Tom Mar 09 '17 at 05:11
  • Oh. Well, OK, in that particular case it may be ill-advised. I don't think there's any reason to avoid it if you need a string and 0-to-many ints or whatever. – Casey Mar 09 '17 at 17:52
  • @Casey: Re. " I don't think there's any reason to avoid it if you need a string and 0-to-many ints or whatever.": *Normally* no reason, yes. That's why I said that the "danger" only applies when "the required Parameter(s) are Type-Compatible with the params Parameter". Although, after further consideration, even in that case and even with Methods with all *required* Parameters before & after changes, there are still ways you could change the Method Signature where existing Calls would still compile (with values passed to unintended Params). The *SAFEST* way is still to use Named Parameters. – Tom Oct 05 '17 at 23:33
10

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);
Sнаđошƒаӽ
  • 16,753
  • 12
  • 73
  • 90
electricalbah
  • 2,227
  • 2
  • 22
  • 36
  • Thanks for your input but I don't think these kind of overloads would be a solution at all since with `params` or without we would just pass a collection type to cover any count of collections. – MasterMastic Apr 01 '14 at 06:54
  • You are right at some extent but what makes it cool is an overload with no input parameter eg int sum1 = addTwoEach(); – electricalbah Apr 01 '14 at 09:20
5

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.

Tshilidzi Mudau
  • 7,373
  • 6
  • 36
  • 49
Ashwini
  • 707
  • 8
  • 5
5

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.

David Anderson
  • 13,558
  • 5
  • 50
  • 76
1

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[] {});
Beniamin Makal
  • 164
  • 1
  • 5
0

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

Manoj Kumar
  • 318
  • 4
  • 14
0

Another example

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

var items = Tokenize(product.Name, product.FullName, product.Xyz)
skjagini
  • 3,142
  • 5
  • 34
  • 63
0

It enhances code brevity. Why be lengthy when you can be concise?

using System;

namespace testingParams
{
    class Program
    {
        private void lengthy(int[] myArr)
        {
           foreach (var item in myArr)
           {
              //...
           }
        }
        private void concise(params int[] myArr) {
           foreach (var item in myArr)
           {
              //...
           }
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            //Why be lengthy...:
            int[] myArr = new int[] { 1, 2, 3, 4, 5 };
            p.lengthy(myArr);
            //When you can be concise...:
            p.concise(1, 2, 3, 4, 5);
        }
    }
}

If you remove the keyword params, the caller code will not work as desired.

Dean P
  • 1,841
  • 23
  • 23