C # - Ошибка компилятора - при назначении int [] для объекта [] - PullRequest
7 голосов
/ 04 сентября 2011
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            object[] obj = new object[3];
            obj[0] = new object();
            obj[1] = "some string";
            obj[2] = 10;

            string[] strings = new string[] { "one", "two", "three" };
            obj = strings; //---> No Error here, Why ?

            int[] ints = new int[] { 1, 2, 3 };
            obj = ints; /*-> Compiler error - Cannot implicitly convert type 'int[]' to 'object[]', Why ?*/ 
        }
    }
}

Я получаю ошибку компилятора при выполнении шага, как показано выше.Но на предыдущем шаге ошибки нет.Может кто-нибудь объяснить мне это поведение?Я использую VS 2010.

РЕДАКТИРОВАТЬ - Ради полноты, опять же, это не скомпилируется - Поддержка отклонений в .NET 4.0 теперь очищена.Можно использовать новые ключевые слова в и в с параметрами общего типа.

    List<object> objectList = new List<object>();
    List<string> stringList = new List<string>();
    objectList = stringList;

Ответы [ 5 ]

6 голосов
/ 04 сентября 2011

Только массивы ссылочных типов (например, String) могут быть назначены массивам других ссылочных типов (например, Object).Поскольку int является типом значения, его массивы не могут быть назначены массивам других типов.

Точнее, это называется ковариация массива .Это работает только тогда, когда битовые комбинации, хранящиеся в массиве, совместимы с типом назначения.Например, все биты в String[] являются ссылками на строки и могут быть безопасно скопированы в ячейки памяти, где хранятся ссылки на объекты.Массив типов значений, однако, хранит фактические данные элементов (а не просто ссылки на них).Это означает, что int[] хранит фактические 32-битные целые числа в элементах массива.Поскольку 32-разрядное целое число нельзя безопасно скопировать в область памяти, где хранится ссылка на объект или любой другой тип, вы не можете назначить их массив массиву любого другого типа.

Обратите внимание, что техническибиты int могут быть безопасно скопированы в ячейку памяти, в которой хранится uint (и наоборот).Это означает, что вы должны быть в состоянии сделать что-то вроде int[] x = new uint[10].На самом деле это не ковариация, и C # не позволяет этого.Однако в CLR это разрешено законом, и вы можете убедить C # позволить вам сделать это, если хотите.

2 голосов
/ 04 сентября 2011

string и object оба являются ссылочными типами.То есть переменная этих типов фактически хранит указатель на другое место в памяти.int является типом значения.То есть данные хранятся непосредственно там, где объявлена ​​переменная.

Это означает, что массив ссылочных типов принципиально отличается от массива типов значений.Массив ссылочных типов хранится в виде массива указателей.Поскольку указатели имеют один и тот же размер, это означает, что переосмысление string[] как простого object[] означает корректировку проверки типа, выполняемой при доступе к элементам в массиве (грубо говоря).

Однаков int[] значения сохраняются в массиве напрямую;значения int объединяются вместе.Указатели не участвуют.Это означает, что для повторной интерпретации int[] как object[] требуется упаковать каждое значение, сохраненное в массиве, в объект.Следовательно, почему вы не можете сделать это с помощью простого приведения или присваивания - это операция O (n), которая создает новый массив.Вместо этого вы можете использовать Array.Copy, который занимается всем боксом для вас.

1 голос
/ 04 сентября 2011

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

Если вы или кто-то еще действительно хотите это сделать (преобразуйте int[]по object[]) по какой-то причине вы можете использовать LINQ следующим образом:

int[] ints = new int[] { 1, 2, 3 };
object[] obj_ints = (from i in ints select i).Cast<object>().ToArray();

;)

1 голос
/ 04 сентября 2011

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

0 голосов
/ 04 сентября 2011

Если у вас установлена ​​Visual Studio, вы найдете спецификацию языка C # в виде файла doc где-то под VC #. Глава 12.5 имеет дело с ковариацией и там говорится

Для любых двух типов ссылок A и B, если неявная ссылка существует преобразование (§6.1.6) или явное ссылочное преобразование (§6.2.4) из А в В, то же самое эталонное преобразование также существует из тип массива A [R] для типа массива B [R], где R - любой заданный спецификатор ранга (но одинаковый для обоих типов массивов). Это отношения известен как ковариация массива.

Возможно, это не ответит на ваш вопрос, но в спецификации было преднамеренное решение сделать это таким образом.

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