Why does passing null to a params method result in a null parameter array?
Asked Answered
C

5

34

I have a method that uses the params keyword, like so:

private void ParamsMethod(params string[] args)
{
    // Etc...
}

Then, I call the method using various combinations of arguments:

                            // Within the method, args is...
ParamsMethod();             // - a string array with no elements
ParamsMethod(null);         // - null (Why is this?)
ParamsMethod((string)null); // - a string array with one element: null
ParamsMethod(null, null);   // - a string array with two elements: null and null
ParamsMethod("s1");         // - a string array with one element: "s1"
ParamsMethod("s1", "s2");   // - a string array with two elements: "s1" and "s2"

I understand all of the cases, except for the second one. Can someone explain why ParamsMethod(null) causes args to be null, instead of an array with one null element?

Carolann answered 26/1, 2012 at 21:44 Comment(2)
Now that you know the answer, you can work on this puzzle. You have two methods, void M(object){} and void M(params object[]){}. You call M(null). Which overload is chosen, what is passed to it, and why?Heavyduty
I've encountered this before. I think just renamed one of the methods. :)Carolann
E
30

A params parameter is only meant to provide a convenient way of specifying values - you can still pass an array reference directly.

Now, null is convertible to either string[] or string, so both interpretations are valid - it's up to the spec which is preferred. The spec states in section 10.6.1.4 that:

  • The argument given for a parameter array can be a single expression that is implicitly convertible to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

  • Alternatively, [...]

In other words, the compiler checks to see whether the argument is valid as the "normal" parameter type first, and only builds an array if it absolutely has to.

Ekaterinodar answered 26/1, 2012 at 21:48 Comment(1)
Also, it's worthwhile to note that many methods which take a parameter array will also have overloads for (object), (object, object) and (object, object, object) - This is to avoid the overhead of constructing an array object for only a few objects, since these overloads will be matched first.Satterlee
D
8

See the C# specification, section 10.6.1.4 Parameter arrays:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.
  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

Since null is implicitly convertible to string[], it will be used as the array.

Furthermore:

When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (§7.5.3.1). The expanded form of a method is available only if the normal form of the method is not applicable and only if a method with the same signature as the expanded form is not already declared in the same type.

which clarifies that the compiler indeed first tries to use the method with an array argument (normal form) before it tries using the argument as an array element (expanded form).

Dickey answered 26/1, 2012 at 21:50 Comment(0)
S
3

The reason for this is that you can pass an array of the appropriate type to a params argument. Since null can be converted to any type, and the array syntax takes precedence, you get null as the value of your parameter.

Explicitly casting it to string, of course, makes it become an element of the array rather than the array itself.

You can try it and see:

private void DoSomething(params IEnumerable[] arr) {
    // ...
}

...

DoSomething(new IEnumerable[] {new int[] {}}); // arr[0] isn't IEnumerable[], it's int[].

And here's an online demo.

Swank answered 26/1, 2012 at 21:48 Comment(0)
A
3

You can pass an array to a params parameter - in fact, it is preferable (I.e. if you pass an object[] to a method that takes params object[], it is the entire parameter, not just the single element). Null is valid as an assignment to an array, so - that binding wins.

Basically, you'll ned to be more explicit.

Amphetamine answered 26/1, 2012 at 21:49 Comment(0)
J
2

From the language specification:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

Since null in ParamsMethod(null) can be implicitly converted to (string[])null, the first rule is the one that gets applied.

Jiminez answered 26/1, 2012 at 21:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.