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

С# params object [] странное поведение

Учитывая этот код

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] strings = new string[] { "Test1", "Test2", "Test3" };

            int[] ints = new int[] { 1, 2, 3, 4 };

            Test(strings);

            Test(ints);
        }

        public static void Test(params object[] objects)
        {
        }
    }
}

И эта страница https://msdn.microsoft.com/fr-ca/library/w5zay9db.aspx

Я бы ожидал (объекты params object []) как массив одного элемента со строкой [] как первый элемент, но когда я отлаживаю, я вижу, что (объекты params object []) есть { "Test1", "Test2", "Test3" }.

Однако, с int [], я получаю объект [] с int [] как первый элемент.

со строками

С ints

Это поведение undefined? Это зависит от версии .Net framework/Mono версии?

4b9b3361

Ответ 1

Приятно найти!

Это поведение undefined?

Нет. Это поведенческое поведение. Странный дизайн, но по дизайну.

Это зависит от версии .Net framework/Mono версии?

Нет. Все версии С# имеют такое поведение.

Это следствие столкновения некоторых интересных правил С#.

Первое соответствующее правило: метод с массивом params может быть вызван либо в "нормальной", либо в "расширенной" форме. Нормальная форма как будто не было "параметров". Расширенная форма принимает параметры и связывает их с массивом, который автоматически генерируется. Если применяются обе формы, то нормальная форма выигрывает над расширенной формой.

Теперь это, возможно, кажется разумным; если у вас есть массив объектов в руке, вероятность хорошая, что вы хотите передать массив объектов, а не массив, содержащий массив объектов.

Второе релевантное правило состоит в том, что С# допускает небезопасную ковариацию массива, когда тип элемента является ссылочным типом. То есть массив строк может быть преобразован в массив объектов неявно. Вы заметите, что это имеет два значения. Во-первых, это означает, что когда у вас есть массив объектов, это может быть массив строк, поэтому, например, черепаха в этот массив объектов может вызвать ошибку типа. Это очень удивительно! Вы ожидаете, что каждый массив объектов может принимать любой объект, но это не так в С#. Некоторые массивы объектов лежат.

Вторая проблема заключается в следующем: поскольку включение этой черепахи в то, что на самом деле представляет собой массив строк, должно бросаться, это означает, что каждый раз, когда вы помещаете что-то в массив базового типа, среда выполнения должна проверять, что типы проверяют. Таким образом, массивные записи на С# накладываются на дорогостоящие записи при каждой записи, так что исчезающее незначительное меньшинство плохой записи может быть обнаружено.

Это беспорядок, и именно поэтому небезопасная ковариация массивов покрывает мой список несчастливых функций С#.

Сочетание этих двух правил объясняет ваши наблюдения. Массив строк преобразуется в массив объектов, и поэтому метод применим в нормальной форме.

Для массива ints, ну, ковариация не применяется к типам значений. Таким образом, массив ints не конвертируется в массив объектов, поэтому метод не применим в его нормальной форме. Но массив ints является объектом, поэтому он применим в расширенной форме.

См. также:

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

Ваш вопрос, возможно, является дубликатом:

Есть ли способ отделить myFunc (1, 2, 3) от myFunc (new int [] {1, 2, 3})?

Ответ 2

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

Test(object1)
Test(object1, object2)
Test(object1,..., objectN)

Итак, вы видите, что нормальное поведение ничего странного. Дополнительная информация по этой ссылке msdn

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

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

Никакие дополнительные параметры не разрешены после ключевого слова params в объявлении метода, и только одно ключевое слово params разрешено в Объявление метода.

Ответ 3

public static void Test(params string[] strings)
{
}

Test(string1)
Test(string1, string2)

и т.д. string1... stringN.