Why C # allows only the last parameter of the method to have a "variable length",

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

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

 T f(params A[] a, params B[] b) 
+6
source share
7 answers

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

Please say that argOne and argTwo must contain inside the method body:

 void Foo( params object[] argOne, params object[] argTwo ) { // whatever } Foo( 1, false, "Hello", new object(), 2.3 ); 
+12
source

Because it would be too difficult to determine when such a design is really allowed.
(When the call will be unambiguous)
Although it would be possible to create a good set of rules, they would be quite complex and difficult to understand. People will eventually ask why case X does not work if it has subtle ambiguity.

For instance:

  • None of the types can be an interface or a general parameter
  • If one type is an enumeration or a numeric type, the other must be a class other than object or Enum
  • If one type is a delegate, the other should not also be a delegation type (both object , Delegate , and MulticastDelegate )
  • One type cannot inherit another
  • All of these rules apply to all types that are implicitly convertible to parameter types.
  • Both types must be sealed or must be value types

(some of these rules can be enforced instead of callsite)

In practice, such a function would have so many limitations to be almost useless.

Consequently, this feature started at -10,000 points .

It would also create a new category of violations. Unlocking a type, adding implicit conversions, or other seemingly trivial things can now break client code.

+8
source

Because of the ambiguity. If you went and did:

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

And you called:

 f(1, 2, 3, 4) 

How does the compiler know where to start, and the other start? You could argue that such cases can still be labeled as compilation errors and still allow explicit cases to continue, but with inheritance this can get complicated and it just doesn't cost. Instead, pass two arrays. I can’t think of any situation that deserves two arrays of parameters, and even then it is syntactic sugar. There is no difference between it and just using arrays.

(Another example:

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

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

+1
source

This will raise the issue and lead to conflicts.

For example, let B inherit from A

As the compiler understands:

 f(A1, A2, ) 

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

I think in theory the compiler can be smart and detect conflicts.
However, initially when .NET and C # were developed, the idea was to try to avoid unambiguous and complex cases like this.

+1
source

There are many edge cases that make this incredible 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 it is impossible to find out where the first parameters [] end, and the following begins.

+1
source

If the "last parameter" has a variable length, your second / third / n parameter, which is not necessary, will be contained in the first according to your sample and will be undefined:

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

b will be contained inside

0
source
 void DoSomething( params object[] p1, params int[] p2 ) { ... } DoSomething( 1, 2, 3 ); 

Consider whether the compiler can resolve this. Can you enter the code "..."? If so, is it readable?

I can tell you: it would be a mess.

0
source

Source: https://habr.com/ru/post/890561/


All Articles