1
void Main()
{
    //Thing(x:1, s:string.Empty, hello:new Hello(), new Hello());
    Thing(x:1, s:string.Empty, hello:new[]{ new Hello(), new Hello()});
}

public void Thing(int x, string s = "", params Hello[] hello)
{
}

public class Hello { }

Why do I need to specify an array to make params work when used with an optional argument or do I? The only reason labels were used is because I originally wanted to exclude the optional parameter

Abbas
  • 14,186
  • 6
  • 41
  • 72
Jaycee
  • 3,098
  • 22
  • 31
  • 1
    Even Jon Skeet wasn't able to come up with an explanation :) http://stackoverflow.com/questions/12747117/optional-argument-followed-by-params?rq=1 – Matten Dec 10 '13 at 15:34

3 Answers3

1

you could just do,

Thing(1, string.Empty, new Hello(), new Hello());

since you are using params.

For that matter all these would be compatible.

Thing(1);
Thing(2, string.Empty);
Thing(3, string.Empty, null);
Thing(4, string.Empty, new Hello());
Thing(-69, "negative feeback", new Hello(), null);
Thing(42, "the meaning of life", new Hello(), new Hello());
Thing(666, theBeast.ToString(), new Hello(), new Hello(), new Hello());
// etc. etc.

From your comment I think your question is actually,

Why do I have to construct the params array when using parameter names?

That question is a duplicate but, in summary its because, thats the way it works.


If you want to omit s and get the benefits of params why not declare the overload,

public void Thing(int x, string s = "", params Hello[] hellos)
{
}

public void Thing(int x, params Hello[] hellos)
{
    this.Thing(x, string.Empty, hellos);
}

Then you can still use params as intended and you don't need to use parameter names.

This functionality is older than optional parameters and largely mitigates your requirement, which I guess is why its never been addressed.

Community
  • 1
  • 1
Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • 1
    You're right but I guess the real question is why he has to provide an array of `Hello` explicitly instead of passing several `Hello`-objects when using named parameters – Abbas Dec 10 '13 at 15:30
  • 1
    ...when the op is using parameter names. – Matten Dec 10 '13 at 15:31
  • @Jodrell True, but I wanted to exclude the second parameter and a more technical explanation if possible. Thanks. – Jaycee Dec 10 '13 at 15:32
  • @Jodrell There's always a way around things, such as the overload, but I wanted to get to the bottom of it :) – Jaycee Dec 10 '13 at 16:13
1

Because that's how params works - technically it's an array parameter that the compiler will generate from a list of arguments for you. The current C# specifications don't support passing multiple values into one named parameter without bundling them. If you want to use the parameter name to mass multiple values you have to bundle the parameters in an array.

These should work:

Thing(x:1, hello:new[]{ new Hello(), new Hello()}); // 2 values
Thing(x:1, hello:new Hello());  // one value
Thing(x:1); // no values

If you think this is a valuable addition to the compiler relative to the cost required to implement it, then feel free to post a suggestion on Microsoft Connect

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • @D Stanley Other than, that's the current compiler implementation, is there an explanation? – Jaycee Dec 10 '13 at 15:40
  • No one has implemented it in the compiler - that's the reason. My guess is either no one suggested it or the _value_ provided does not justify the _cost_ of implementing it -either in opportunity cost, technical cost, or impact to other features. Features are not free. – D Stanley Dec 10 '13 at 15:50
  • 1
    @Jaycee I can think of several more pressing enhancements, you can overload your functions. – Jodrell Dec 10 '13 at 16:08
  • Well, it's not in the compiler because it's not in the spec. But to be honest it's probably not in the spec because of the cost to implement it in the compiler. – Rawling Dec 10 '13 at 16:15
1

Well, named arguments and params have conflicting rules: Named arguments may appear in any order, and params must be at the end. According to the former, we should be able to do this:

Thing(1, hello:new Hello(), new Hello(), s:string.Empty);

The compiler could certainly work out how to interpret that, but it's less clear to the reader than having params at the end as they normally are. But if hello: was forced to be placed at the end, this would be inconsistent with named arguments and remove some of the flexibility you would otherwise have.

So in short, I think requiring an explicit array is a compromise that preserves the most consistency.

nmclean
  • 7,564
  • 2
  • 28
  • 37