ILists переданы по значению? - PullRequest
6 голосов
/ 24 февраля 2010

Передача значения типа параметров в функции в c # производится по значению, если только вы не используете ключевое слово ref или out для параметра. Но относится ли это также к ссылочным типам ?

В частности, у меня есть функция, которая принимает IList<Foo>. Будет ли список, переданный моей функции, копией списка с копией содержащихся в нем объектов? Или изменения в списке также применимы к абоненту? Если так - есть ли умный способ передать копию?

public void SomeFunction()
{
    IList<Foo> list = new List<Foo>();
    list.Add(new Foo()); 
    DoSomethingWithCopyOfTheList(list);
    ..
}

public void DoSomethingWithCopyOfTheList(IList<Foo> list)
{
    // Do something
}

Ответы [ 6 ]

16 голосов
/ 24 февраля 2010

Все параметры передаются по значению, если вы явно не используете ref или out. Однако, когда вы передаете экземпляр ссылочного типа, вы передаете ссылку по значению. То есть сама ссылка копируется, но, поскольку она по-прежнему указывает на тот же экземпляр, вы все равно можете изменить экземпляр с помощью этой ссылки. То есть экземпляр не копируется. Ссылка есть.

Если вы хотите сделать копию самого списка, List<T> имеет удобный конструктор , который принимает IEnumerable<T>.

10 голосов
/ 24 февраля 2010

Ты не одинок; это смущает многих людей.

Вот как мне нравится думать об этом.

Переменная - это место хранения.

Переменная может хранить что-то определенного типа.

Существует два типа типов: типы значений и ссылочные типы.

Значение переменной ссылочного типа является ссылкой на объект этого типа.

Значением переменной типа value является объект этого типа.

Формальный параметр - это разновидность переменной.

Существует три вида формальных параметров: параметры-значения, параметры ref и параметры out.

Когда вы используете переменную в качестве аргумента, соответствующего параметру значения, значение переменной копируется в хранилище, связанное с формальным параметром. Если переменная имеет тип значения, то создается копия значения. Если переменная имеет ссылочный тип, то создается копия ссылки, и две переменные теперь ссылаются на один и тот же объект. В любом случае создается копия значения переменной.

При использовании переменной в качестве аргумента, соответствующего параметру out или ref , параметр становится псевдонимом для переменной . Когда вы говорите:

void M(ref int x) { ...}
...
int y = 123;
M(ref y);

Вы говорите: «x и y теперь одна и та же переменная ». Они оба относятся к одному и тому же месту хранения .

Я считаю, что гораздо легче понять, чем думать о том, как на самом деле реализован псевдоним, - передав управляемый адрес переменной в формальный параметр.

Это ясно?

4 голосов
/ 24 февраля 2010

Список передается по ссылке, поэтому, если вы измените список в SomeFunction, вы также измените список для вызывающего абонента.

Вы можете создать копию списка, создав новый:

var newList = new List<Foo>(oldList);
2 голосов
/ 24 февраля 2010

ваш список передается по ссылке. Если вы хотите передать копию списка, вы можете сделать:

IList<Foo> clone = new List<Foo>(list);

если вы добавите / удалите элементы в клоне, список не изменится но модификации самих элементов будут учтены в обоих списках.

1 голос
/ 24 февраля 2010

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

Для решения вашей проблемы вы можете явно создать копию и передать эту копию своей функции, или вы можете использовать:

list.AsReadOnly();
0 голосов
/ 24 февраля 2010

При передаче типов ссылок вы передаете ссылку. Это важная концепция.

Если вы передаете ссылку

byref, вы передаете ссылку (указатель) напрямую.

byval, вы передаете копию ссылки (указатель).

Ссылка не является ссылкой на экземпляр. Ссылка на указатель аналогична.

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

...