Почему 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

PrintLength(s, s);

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

PrintLength(нуль);

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

PrintLength(ноль, ноль);

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

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

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

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам