Почему в методе можно изменять массив без передавания его по ссылке?

177
16 июля 2018, 22:30

Имеются в C# такие функции как

Array.Copy(source2,2,target,3,2);
source.CopyTo(target,0);

Их документация гласит следующее

public static void Copy(Array sourceArray, long sourceIndex, Array destinationArray, long destinationIndex, long length);

Копирует диапазон элементов из массива System.Array, начиная с заданного индекса источника, и вставляет его в другой массив System.Array, начиная с заданного индекса назначения. Длина и индексы задаются как 32-битовые целые числа.

Во 2 случае аналогично:

public void CopyTo(Array array, int index);

Копирует все элементы текущего одномерного массива в заданный одномерный массив начиная с указанного индекса в массиве назначения.Индекс задается как 32-битовое целое число.

Их вызов:

Array.Copy(source,2,target,2,2);
source.CopyTo(target,0);

Однако суть не в этом все эти методы возвращают Void и изменяют содержимое одного из аргументов однако в документации что то это не показано ведь как правило если я правильно понимаю здесь должно быть по правилам быть так:

Array.Copy(source,2,ref target,2,2);//передача по ссылке
source.CopyTo(ref target,0);//передача по ссылке

Почему это не отражается в коде по какому правилу изменяет содержимое target без ссылки

Answer 1

Ничто не мешает изменять изменять элементы переданного массива. Они являются частью объекта массива и доступны через переданную в метод ссылку. Т.к. сама ссылка не изменяется, то передавать ее по ссылке (ref) не нужно.

Например такой метод успешно изменит первый элемент массива:

void Change(int[] array) 
{
    //изменяем элемент массива, можно без ref
    array[0] = 1;
}

Использование ref

ref позволяет изменить объект массива, на который ссылается переменная target.
Массив — ссылочный тип, соответственно в метод передается ссылка на массив. Ссылка по-умолчанию передается по значению и изменения ссылки не влияют на переданное значение. Для того чтобы сама ссылка передавалась по ссылке Вам понадобится ref.

Рассмотрим два метода (с ref и без):

void ReasssignIncorrectly(int[] array) 
{
    //пересоздание массива, т.к. аргумент не ref, это не окажет влияния на переданную ссылку
    array = new[]{2};
}
void ReasssignCorrectly(ref int[] array) 
{
    //пересоздается успешно, т.к. ref
    array = new[]{3};
}

ReasssignIncorrectly не окажет влияния на переданную переменную.

Наример, такой код:

var a = new int[1];
Console.WriteLine(a[0]);
Change(a);
Console.WriteLine(a[0]);
//не изменит массив
ReasssignIncorrectly(a);
Console.WriteLine(a[0]);
ReasssignCorrectly(ref a);
Console.WriteLine(a[0]);

Выведет

0
1
1
3

Демонстрация на Ideone: https://ideone.com/Gxz1rq

READ ALSO
Создание торрент-файла из магнет-ссылки C#

Создание торрент-файла из магнет-ссылки C#

Существуют ли библиотеки, позволяющие из magnet-ссылки получить полноценный торрент-файл? Раньше доводилось работать с BencodeNET, но, я так понимаю,...

196
Зачем мы реализовываем IEquatable<T>, если Equals() есть в Object?

Зачем мы реализовываем IEquatable<T>, если Equals() есть в Object?

Разбирая тему обобщений (по Шиелду 40), потребовалось написать обобщённый метод, который вернет логическое значение true, если в массиве содержится...

205
Не выполняется запрос INSERT в c#

Не выполняется запрос INSERT в c#

База данных AccessПервичный ключ id

204
Вывод в консоль списка процессов

Вывод в консоль списка процессов

Обычное консольное приложениеNET Core

183