#c# #.net #language-specifications #system.array
#c# #.net #язык-спецификации #system.array
Вопрос:
int[] array1 = new[] { 1, 2, 3 };
int[] array2 = (int[])array1.Clone();
array2[0] = 9;
Debug.Assert(array1[0] != array2[0]);
Это работает нормально. Clone()
выполняется неглубокая копия, но типы массивов являются типами значений, поэтому они тоже клонируются.
Мой вопрос в том, является ли это явным в спецификации языка или это просто артефакт текущей реализации?
Мои сомнения связаны с System.Array
поддержкой типов значений «невидимо» за кулисами с помощью обобщений во время выполнения. Глядя на общедоступные методы, можно ожидать, что типы значений будут помещены в коробку.
Комментарии:
1. Почему вы ожидаете, что типы значений будут помещены в коробку?
2. Значения типа значения ведут себя как значения, а не ссылки. Это не изменится внезапно, если сохранить их в массиве. Или любой другой тип класса. Конечно, очень по дизайну.
Ответ №1:
Это работает, потому что абсолютно невозможно, чтобы два массива могли использовать один и тот же экземпляр типа значения.
В спецификации конкретно не указано, как Array.Clone
ведет себя с типами значений по сравнению с тем, как он ведет себя со ссылочными типами. Но в спецификации указано, что экземпляры типов значений копируются побитово при назначении. Поэтому при array1[i]
копировании в array2[i]
вы получаете клон экземпляра по индексу i
. Всегда.
Однако имейте в виду, что если тип значения имеет поле ссылочного типа, будет скопирована только ссылка, а не экземпляр ссылочного типа.
мой вопрос заключался в том, будет ли потенциальный бокс по массиву отрицать это. т.е. копируются ссылки в штучной упаковке, а не базовый тип значения.
Даже если array1[i]
он был помещен в коробку во время клонирования, его нужно было бы распаковать, чтобы в итоге вы получили a int[]
, а не an object[]
. Значение будет клонировано при распаковке.
Комментарии:
1. Я согласен с тем, что назначения типов значений копируются по битам, но мой вопрос заключался в том, будет ли потенциальный бокс по массиву отрицать это. т.е. копируются ссылки в штучной упаковке, а не базовый тип значения.
2. @GazTheDestroyer Я обновил свой ответ. Но опять же, это сводится к тому, что я сказал в первом предложении: «нет абсолютно никакого способа, чтобы два массива могли использовать один и тот же экземпляр типа значения». Экземпляр типа значения находится внутри его контейнера. Итак, если у вас есть два контейнера (
array1
иarray2
), и у каждого контейнера есть свое собственное пространство памяти, anint
не может находиться в двух местах одновременно.3. Да, спасибо за ваши разъяснения. Я поиграл с некоторым кодом и понял, что суть моего замешательства заключалась в том, что я думал, что есть какой-то способ обновить «содержимое» значения в штучной упаковке без изменения самой ссылки. Вы не можете, он просто получает новое «поле».