1

Столкнулся со следующей проблемой:

Экземпляр var checkRow, получает значение itemRows, далее, в метод передаются оба объекта, из которых ref itemRows

При выполнении метода, изменении данных в checkRow, меняются значения в itemRows

// В данном методе инициализируются объекты и вызывается метод

 var itemRows = GetInfoFromXml.GetUkdRows(node);
 var checkRow = itemRows;

 //var checkRow = GetInfoFromXml.GetUkdRows(node);
 checkRow = GetTanderUkdOwnRow(ref itemRows, checkRow);

// Сам метод

private static CalcItemRow[] GetTanderUkdOwnRow(ref CalcItemRow[] itemRows, CalcItemRow[] checkRow)
    {
        foreach (var row in checkRow)
        {
            row.PosCase.Replace("(док)", "программа");
        }

        checkRow[0] = Recalculation(ref itemRows[0], checkRow[0]);
        checkRow[0].PosName = "Расчёты программой:";
        checkRow[1] = Recalculation(ref itemRows[1], checkRow[1]);
        checkRow[2] = IncreasingRow(ref itemRows[2], checkRow[2], checkRow[0], checkRow[1]);
        checkRow[3] = DegreasingRow(ref itemRows[3], checkRow[3], checkRow[0], checkRow[1]);

        return checkRow;
    }

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

При выполнении строки checkRow[0].PosName = "Расчёты программой:";, [0] объект itemRows так же получает указанное значение параметра, по какой причине - не совсем понятно. Аналогично при любых изменениях checkRow

Если checkRow задавать с помощью закомменченной строки, всё выполняется согласно логике.

Это корректное поведение? Если да - просьба поделиться литературой. При воспроизведении ситуации с int, всё отрабатывает нормально.

  • 1
    Так у вас же itemRows и checkRow - это один и тот же массив. – Pavel Mayorov Oct 02 '18 at 07:16
  • 2
    Да это корректное поведение, литература — здесь: https://ru.stackoverflow.com/a/416585/218063 – Андрей NOP Oct 02 '18 at 07:17
  • @PavelMayorov Изначально - да, далее изменяю большинство данных checkRow, в itemRow, изменяется только 1н параметр, при определённом кейсе.

    А при выполнении текущего кода, изменяется всё.

    Как говорил ранее - изначально передавал только ref itemRows, уже в теле метода создавал новую переменную и присваивал (копировал) itemRows.

    – Аркадий Карабанов Oct 02 '18 at 07:19
  • @АндрейNOP а есть ссылка на конкретно данный кейс? – Аркадий Карабанов Oct 02 '18 at 07:20
  • Вы можете сотню раз скопировать ссылку на массив, но сам массив от этого не скопируется, вся эта сотня ссылок будет указывать на один и тот же массив – Андрей NOP Oct 02 '18 at 07:25
  • @АндрейNOP Не совсем понял: Я получаю данные в ItemRow, далее создаю новый массив checkRow и присваиваю данные из ItemRow. В данном случае, не происходит копирование ссылки, а создаётся новый объект (на сколько я понимаю).

    Так же пробовал копировать через Clone и CopyTo, не помогло.

    – Аркадий Карабанов Oct 02 '18 at 07:31
  • 5
    далее создаю новый массив checkRow - где? Эта строка var checkRow = itemRows; не создает новый массив. Она создает копию ссылки на массив. Почитайте уже, наконец, литературу. Тот же Троелсен, глава 4, параграф "Типы значений и ссылочные типы" – Андрей NOP Oct 02 '18 at 07:35
  • @АндрейNOP спасибо за информацию, ошибку понял – Аркадий Карабанов Oct 02 '18 at 07:46
  • @АндрейNOP может, ответ напишете? ) – Nick Volynkin Oct 02 '18 at 08:30
  • @NickVolynkin, эх не хотел, но ладно :) – Андрей NOP Oct 02 '18 at 08:59

1 Answers1

1

Да, поведение корректное.

Несколько заблуждений вижу в вопросе вашем я:

  1. Такой код:

    var checkRow = itemRows;
    

    не делает копию массива (или любого другого ссылочного типа, да, массив является ссылочным типом). Этот код копирует ссылку на массив, но массив по прежнему существует в единственном экземпляре и следующий код:

    checkRow[0] = 777;
    Console.WriteLine(itemRows[0]);
    

    выведет 777. Ссылки разные, но указывают на один и тот же массив в памяти, ок?

  2. Передача ссылочного типа в метод по значению делает то же самое, т. е. создает копию ссылки и объект остается существовать в памяти так же в единственном экземпляре. Если вы будете внутри метода менять состояние этого объекта, то все, кто имеют на него ссылку, эти изменения увидят. ref-параметры в вашем случае не нужны, да и не нужны они в подавляющем большинстве случаев.

  3. Даже если вы скопируете массив, т. е. создадите новый экземпляр, то элементы этого массива вполне могут всё так же ссылаться на всё те же объекты, которые лежат в первом массиве (у вас ведь массив элементов ссылочного типа?):

    var newArray = oldArray.ToArray();
    newArray[0].SomeProperty = "New Value";
    Console.WriteLine(oldArray[0].SomeProperty);
    

    Выведет New Value, т. к. хоть массивы и разные, но и в первом и во втором нулевой элемент ссылается на один и тот же экземпляр класса.

  • Несколько заблуждений вижу в вопросе вашем я мастера сразу видно :) – tym32167 Oct 02 '18 at 09:01