Tomas Ramirez Sarduy
Tomas Ramirez Sarduy

Reputation: 17471

Why C# allows that only the last parameter in a method is of "variable length"

From what I know, C# allows that only the last parameter of a method is of "variable length", for example:

T f(A a, params B[] b) allows that if you have A r; .... B x, y, z; .... you can call f like f (r, x, y, z). Why C# doesn't also define something like:

T f(params A[] a, params B[] b)

Upvotes: 7

Views: 3851

Answers (7)

SLaks
SLaks

Reputation: 887305

Because it would be too complicated to determine when such a construction is actually allowed.
(When the call would be unambiguous)
Although it would be possible to create a good set of rules, they would be rather complicated and difficult to understand. People would end up asking why case X doesn't work, if it has a subtle ambiguity.

For example:

  • Neither type can be an interface or generic parameter
  • If one type is an enum or a numeric type, the other must be a class other than object or Enum
  • If one type is a delegate, the other must not also be a delegate type (nor object, Delegate, nor MulticastDelegate)
  • One type cannot inherit the other
  • All of these rules apply to any types implicitly convertible to the parameter types
  • Both types must be sealed or must be value types

(some of these rules could be enforced at the callsite instead)

In practice, such a feature would have so many restrictions as to be almost worthless.

Therefore, this feature would start with -10,000 points.

It would also create a whole new category of breaking changes. Unsealing a type, adding implicit conversions, or other seemingly trivial things could now break client code.

Upvotes: 9

Alex Aza
Alex Aza

Reputation: 78447

It would pose question and lead to conflicts.

For example, let's say B inherits from A.

How would compiler understand:

f(A1, A2, B1, B2)

Would it mean f({A1, A2}, {B1, B2}) or f({A1, A2, B1}, {B2})?

I think theoretically compiler could be smart and detect conflicts.
However, originally when .NET and C# itself were designed the idea was to try to avoid unambiguous and tricky cases like this.

Upvotes: 1

james_bond
james_bond

Reputation: 6908

If the 'last parameter' is of variable length, your second/third/n parameter woundn't be necessary 'cause would be contained into the first one according to your sample and would be ambigous:

T f(params A[] a, params B[] b)

b would be contained within a

Upvotes: 0

Ed Swangren
Ed Swangren

Reputation: 124632

Because how would the compiler know when the variable arguments for the first parameter stop?

Pleas tell me what argOne and argTwo should contain inside of the method body:

void Foo( params object[] argOne, params object[] argTwo )
{
    // whatever
} 

Foo( 1, false, "Hello", new object(), 2.3 );

Upvotes: 12

Marino Šimić
Marino Šimić

Reputation: 7342

void DoSomething( params object[] p1, params int[] p2 )
{
...   
} 

 DoSomething( 1, 2, 3 );

Think if the compiler could resolve that. Can you code the '...' part? If yes, would it be readable?

I can tell you: It would be a mess.

Upvotes: 0

agent-j
agent-j

Reputation: 27913

There are many edge cases that make this an improbable feature. Consider this example:

public static class Coolifier
{
  public static void BeCool<A,B>(params A[] a, params B[] b)
  {
  }
}

Coolifier.BeCool<string,string> ("I", "don't", "work.", "DO", "I", "?");

The example shows how there is no way to know where the first params [] ends and the next begins.

Upvotes: 1

Ry-
Ry-

Reputation: 224877

Because of ambiguity. If you went and did:

T f(params int[] a, params int[] b)

And you called:

f(1, 2, 3, 4)

How would the compiler know where one started and the other began? You could argue that such cases could still be flagged as compilation errors and still allow the unambiguous cases to continue, but with inheritance it could get complicated and it just isn't worth it. Pass two arrays instead. I can't think of any situation that would merit two parameter arrays, and even then, it's syntactic sugar. There's no difference between it and just using arrays instead.

(Another example:

T f(params string[] a, params object[] b);

string inherits from object. This is still ambiguous...)

Upvotes: 1

Related Questions