Почему params ведет себя так? - PullRequest
22 голосов
/ 06 февраля 2010

Выход

1

2

null

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 ]

28 голосов
/ 06 февраля 2010

Это довольно часто задаваемый вопрос. Подробнее см. В разделах 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" });

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

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

5 голосов
/ 06 февраля 2010

Работает как задумано, я бы сказал:

PrintLength (с);

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

PrintLength (s, s);

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

PrintLength (нуль);

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

PrintLength (null, null);

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

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

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

4 голосов
/ 06 февраля 2010

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

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

Редактировать:

Вероятно, поэтому: Вы можете отправить разделенный запятыми список аргументов типа, указанного в объявлении параметра, или массив аргументов указанного типа. http://msdn.microsoft.com/en-us/library/w5zay9db.aspx

0 голосов
/ 06 февраля 2010

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

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

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

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

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

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