Как мне передать массив по значению?Разве Клон () не обескуражен? - PullRequest
3 голосов
/ 30 ноября 2011

Я отлаживал свою программу на C # и через несколько бесполезных промежутков времени обнаружил, что ошибка возникла из-за «случайной» передачи массива по ссылке, а не по значению.

Вот некоторый псевдокод:

//1st pass
currentVertices = levels[0].vertices;   
currentVertices[0].Position.Z -= 10;

//2nd pass
currentVertices = levels[1].vertices;
currentVertices[0].Position.Z -= 10;

//3rd pass
currentVertices = levels[0].vertices;
currentVertices[0].Position.Z -= 10;  

//currentVertices[0].Position.Z is now 10 less than expected;
//20 less than it started. Further loops will increase the difference in expected
//value.

Я не ожидал, что передал массив по ссылке, но все равно случайно сделал это.

Есть ли способ назначить массив по значению вместо ссылки?Я знаю, что мог бы пройтись по обоим массивам, назначая каждый термин индивидуально, но это кажется излишне сложным.Я вполне уверен, что функция Clone (), ну, клонирует, значения без соответствующих ссылок, но разве это единственный способ присвоения по значению?Т.е. currentVertices = levels[1].vertices.Clone();

Разве Clone () вообще не рекомендуется?Как лучше всего передавать массивы по значению?

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

Как один из моих друзей-модераторовзаметил,

«Я вижу, вы решили пройти через ссылку путем обхода.»

Ответы [ 3 ]

5 голосов
/ 30 ноября 2011

Ну, в C # только типы значений передаются "по значению". (Это упрощение, но это хороший способ взглянуть на это.) Все остальное на самом деле является ссылкой, которая передается по значению, что похоже на передачу указателя. (Обратите внимание, что это отличается от передачи «по ref», что позволило бы обновить переменную в вызывающем методе.)

У вас есть два варианта:

  1. рефакторинг вашего кода, чтобы избежать изменения объектов в массиве
  2. глубокий клон массива

Это примерно в том порядке, который я бы рекомендовал.

3 голосов
/ 30 ноября 2011

Есть ли способ назначить массив по значению, а не по ссылке?

Нет. переменные ссылочных типов (а System.Array - ссылочный тип) ссылаются на их экземпляры.


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

Даже если вы позвоните Клон, это мелкая копия . Клон не делает копии содержимого массива.

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

2 голосов
/ 30 ноября 2011

Если вам действительно нужно передать новый массив в функцию, .Clone() - самый быстрый способ сделать это. В этой ситуации, однако, я бы, как правило, вместо этого использовал Array.AsReadOnly, чтобы получить оболочку Collection вокруг массива.

Как MSDN описывает в отношении AsReadOnly:

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

Коллекция, доступная только для чтения, - это просто коллекция с оболочкой, которая предотвращает изменение коллекции; поэтому, если в базовую коллекцию вносятся изменения, коллекция, доступная только для чтения, отражает эти изменения.

Этот метод является операцией O (1).

...