Почему params ведут себя так?

Выход

1

2

нулевым

2

код

class Program
{ 
 static void Main(String[] args)
 {
 String s = null;
 PrintLength(s);
 PrintLength(s, s);
 PrintLength(null);
 PrintLength(null, null); 
 Console.ReadKey();
 }
 private static void PrintLength(params String[] items)
 {
 Console.WriteLine(items == null ? "null" : items.Length.ToString());
 } 
}
4 ответа

Это довольно часто задаваемый вопрос. Подробности см. В разделах 7.4.1 и 7.4.3.1 спецификации.

Вкратце: метод с массивом params применим либо в его "нормальной форме", либо в "расширенной форме". То есть вы можете сказать

PrintLength(new string[] {"hello"}); // normal form
PrintLength("hello"); // expanded form, translated into normal form by compiler.

При вызове, который применим в обеих формах, компилятор всегда выбирает нормальную форму по расширенной форме.

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

void M(params object[] x) {}

Как бы вы фактически передали нулевой массив этой вещи, если бы всегда выбирали расширенную форму? Это было бы невозможно!

Предположим, вы сказали

M(new object[] { "hello" });

и мы всегда выбираем расширенную форму. Что бы это сделало? Ну, массив объектов - это объект, поэтому он будет выбирать расширенную форму - он сделает другой массив, обернет это в массив и передаст это!

Выбор расширенной формы над нормальной формой приводит к сумасшедшим результатам. Всегда выбирать нормальную форму по расширенной форме - это более разумная вещь.


Он работает так, как я думал:

PrintLength (с);

Вы передаете одну строку, которая является нулевой - внутри вашего метода, items не будет null - это массив одного элемента - строки типа - значения null

PrintLength (s, s);

Одинаковая история здесь - вы передаете два элемента, поэтому items в вашем методе будет представлять собой массив из двух строк - оба из которых имеют нуль, но массив не

PrintLength (нуль);

Это, очевидно, интерпретируется как одно значение NULL, и поэтому items имеет значение null. Вы не передаете массив, ни элемент строки типа - вы просто передаете нулевое значение как таковое.

PrintLength (null, null);

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

Это немного озадачивает, может быть, но действительно: то, что вам нужно проверить в вашем методе PrintLength, заключается не в том, является ли ваш items в целом нулевым, но действительно ли фактические значения items[0] и т.д. нуль.

Что является немного странным, может быть, или интуитивно понятным вначале - факт, что одно явное "нулевое" значение рассматривается как "null", а не массив одного элемента значения null. Почему это так, и может ли это быть реализовано по-другому - я не знаю, честно говоря.


PrintLength(null) передает нулевой массив, где as PrintLength(null, null) передает string[] с длиной двух, содержащей два объекта null string. Это будет то же самое, что передать new string[] { null, null }

Хмм, читал, что я написал, может быть, это не отвечает на ваш вопрос.

Изменить:

Вероятно, поэтому: вы можете отправить список аргументов типа, указанного в объявлении параметра, или массив аргументов указанного типа.

http://msdn.microsoft.com/en-us/library/w5zay9db.aspx


Как сказано в ответе:

  • 1: массив строк с одним элементом в нем - элемент null

  • 2: массив строк с двумя элементами в нем, оба элемента равны null

  • null: null передается в метод, а не массив

  • 2: массив нулей передается в метод

licensed under cc by-sa 3.0 with attribution.