Почему C # допускает, что только последний параметр метода имеет «переменную длину» - PullRequest
6 голосов
/ 15 июня 2011

Из того, что я знаю, C # допускает, что только последний параметр метода имеет "переменную длину", например:

T f(A a, params B[] b) позволяет, если у вас есть A r; .... B x, y, z; ...., вы можете вызвать f как f (r, x, y, z). Почему C # также не определяет что-то вроде:

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

Ответы [ 7 ]

12 голосов
/ 15 июня 2011

Потому что как компилятор узнает, когда переменные аргументов для первого параметра остановятся?

Пожалуйста, скажите мне, что argOne и argTwo должны содержать внутри тела метода:

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

Foo( 1, false, "Hello", new object(), 2.3 );
9 голосов
/ 15 июня 2011

Поскольку было бы слишком сложно определить, когда такая конструкция действительно разрешена.
(Когда вызов был бы однозначным)
Хотя было бы возможно создать хороший набор правил, они были бы весьмасложный и трудный для понимания.Люди в конечном итоге спрашивают, почему регистр X не работает, если он имеет тонкую неоднозначность.

Например:

  • Ни один тип не может быть интерфейсомили универсальный параметр
  • Если один тип является перечислением или числовым типом, другой должен быть классом, отличным от object или Enum
  • Если один тип является делегатом, другойтакже не должен быть типом делегата (ни object, Delegate, ни MulticastDelegate)
  • Один тип не может наследовать другой
  • Все эти правила применяются к любым типам, неявно конвертируемымк типам параметров
  • Оба типа должны быть sealed или должны быть значениями

(некоторые из этих правил могут применяться на месте вызова)

На практике такая функция будет иметь столько ограничений, что будет почти бесполезной.

Поэтому эта функция будет начинаться с -10 000 баллов .

Она также создастцелая новая категория переломных изменений.Распечатывание типа, добавление неявных преобразований или другие, казалось бы, тривиальные вещи теперь могут нарушить работу клиентского кода.

1 голос
/ 15 июня 2011

Есть много крайних случаев, которые делают эту невероятную особенность.Рассмотрим этот пример:

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", "?");

В примере показано, как невозможно узнать, где заканчиваются первые params [] и начинается следующий.

1 голос
/ 15 июня 2011

Это поставит вопрос и приведет к конфликтам.

Например, скажем, B наследуется от A.

Как бы компилятор понял:

f(A1, A2, B1, B2)

Это будет означать f({A1, A2}, {B1, B2}) или f({A1, A2, B1}, {B2})?

Я думаю, что теоретически компилятор может быть умным и обнаруживать конфликты.
Однако изначально, когда были разработаны сами .NET и C #, идея состояла в том, чтобы попытаться избежать однозначных и хитрых случаев, подобных этому.

1 голос
/ 15 июня 2011

Из-за двусмысленности. Если вы пошли и сделали:

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

И вы позвонили:

f(1, 2, 3, 4)

Как компилятор узнает, где один начался, а другой начался? Можно утверждать, что такие случаи все еще могут быть помечены как ошибки компиляции и все еще позволяют однозначным случаям продолжаться, но с наследованием это может усложниться, и это просто не стоит. Вместо этого передайте два массива. Я не могу вспомнить ни одной ситуации, которая заслуживала бы двух массивов параметров, и даже тогда это синтаксический сахар. Нет никакой разницы между этим и просто использованием массивов.

(Другой пример:

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

string наследуется от object. Это все еще неоднозначно ...)

0 голосов
/ 15 июня 2011
void DoSomething( params object[] p1, params int[] p2 )
{
...   
} 

 DoSomething( 1, 2, 3 );

Подумайте, может ли компилятор разрешить это. Можете ли вы кодировать часть «...»? Если да, будет ли это читабельным?

Я могу вам сказать: это будет беспорядок .

0 голосов
/ 15 июня 2011

Если «последний параметр» имеет переменную длину, ваш второй / третий / n параметр не будет необходим, потому что он будет включен в первый в соответствии с вашей выборкой и будет неоднозначным:

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

b будет содержаться в пределах

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...