Подтвердить что ты не робот

Почему передача null в метод params приводит к массиву нулевых параметров?

У меня есть метод, который использует ключевое слово 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, а не массив с одним нулевым элементом?

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

Далее

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

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

Ответ 3

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

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

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

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

...

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

И здесь онлайн-демонстрация.

Ответ 4

Вы можете передать массив параметру params - на самом деле, это предпочтительнее (Т.е. если вы передадите объект [] методу, который принимает объект params [], это параметр цели целых, а не только один элемент). Null является действительным как назначение массиву, поэтому - эта привязка выигрывает.

В принципе, вы не будете более явными.

Ответ 5

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

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

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

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

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