Почему передача значения null в метод params приводит к массиву пустых параметров? - PullRequest
30 голосов
/ 27 января 2012

У меня есть метод, который использует ключевое слово params, например:

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

Затем я вызываю метод, используя различные комбинации аргументов:

                            // 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"

Я понимаю все случаи, кроме второго. Может кто-нибудь объяснить, почему ParamsMethod(null) заставляет args быть null вместо массива с одним нулевым элементом?

Ответы [ 5 ]

30 голосов
/ 27 января 2012
Параметр

A params предназначен только для предоставления удобного способа задания значений - вы все равно можете напрямую передавать ссылку на массив.

Теперь null можно преобразовать в string[] или * 1006.*, так что обе интерпретации действительны - это зависит от спецификации, которая является предпочтительной.В разделе 10.6.1.4 спецификация гласит:

  • Аргумент, заданный для массива параметров, может быть одним выражением, которое неявно преобразуется в тип массива параметров.В этом случае массив параметров действует в точности как параметр значения.

  • В качестве альтернативы [...]

В другихсловами, компилятор сначала проверяет, является ли аргумент допустимым в качестве «нормального» типа параметра, и создает массив только в том случае, если это абсолютно необходимо.

8 голосов
/ 27 января 2012

См. Спецификацию C #, раздел 10.6.1.4. Массивы параметров :

Массив параметров позволяет указывать аргументы одним из двух способов при вызове метода:

  • Аргумент, заданный для массива параметров, может быть одним выражением, которое неявно преобразуется (§6.1) в тип массива параметров. В этом случае массив параметров действует в точности как параметр значения.
  • Альтернативно, вызов может указать ноль или более аргументов для массива параметров, где каждый аргумент является выражением, которое неявно преобразуется (§6.1) в тип элемента массива параметров. В этом случае вызов создает экземпляр типа массива параметров с длиной, соответствующей количеству аргументов, инициализирует элементы экземпляра массива с заданными значениями аргументов и использует вновь созданный экземпляр массива в качестве фактического аргумента.

Поскольку null неявно преобразуется в string[], он будет использоваться в качестве массива.

Кроме того:

При выполнении разрешения перегрузки метод с массивом параметров может быть применим либо в его обычной форме, либо в расширенной форме (§7.5.3.1). Расширенная форма метода доступна только в том случае, если обычная форма метода неприменима и только если метод с такой же сигнатурой, что и расширенная форма, еще не объявлен в том же типе.

, который поясняет, что компилятор действительно сначала пытается использовать метод с массивом аргумент (нормальная форма), прежде чем он пытается использовать аргумент в качестве массива элемент (расширенная форма).

3 голосов
/ 27 января 2012

Вы можете передать массив параметру params - на самом деле, это предпочтительнее (т. Е. Если вы передаете объект [] методу, принимающему params object [], это параметр whole , не только один элемент). Нуль действителен как присваивание массиву, поэтому - победит привязка.

По сути, вам нужно быть более явным.

3 голосов
/ 27 января 2012

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

Явное приведение к string, конечно, делает его элементом массива, а не самим массивом.

Вы можете попробовать и посмотреть:

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

...

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

А вот и демоверсия онлайн.

2 голосов
/ 27 января 2012

Из спецификации языка:

Массив параметров позволяет указывать аргументы одним из двух способов при вызове метода:

  • Заданный аргументдля массива параметров может быть одно выражение, которое неявно преобразуется (§6.1) в тип массива параметров.В этом случае массив параметров действует в точности как параметр значения.

  • В качестве альтернативы, вызов может указывать ноль или более аргументов для массива параметров, где каждый аргумент является выражением, которое неявнообратимый (§6.1) к типу элемента массива параметров.В этом случае вызов создает экземпляр типа массива параметров с длиной, соответствующей количеству аргументов, инициализирует элементы экземпляра массива с заданными значениями аргументов и использует вновь созданный экземпляр массива в качестве фактического аргумента.

Поскольку null в ParamsMethod(null) может быть неявно преобразовано в (string[])null, первое правило, которое применяется, -

...