列表是否按值传递?

时间:2010-02-24 09:10:07

标签: c# parameters pass-by-reference

Value Type参数传递给c#中的函数是值,除非您在参数上使用ref或out关键字。但这也适用于Reference Types吗?

具体来说,我有一个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 个答案:

答案 0 :(得分:16)

除非您明确使用refout,否则所有参数都会按值传递。但是,当您传递引用类型的实例时,您将按值传递引用。即引用本身被复制,但由于它仍然指向同一个实例,您仍然可以通过此引用修改实例。即实例未复制。参考是。

如果您想复制一份列表本身,List<T>有一个handy constructor,需要IEnumerable<T>

答案 1 :(得分:10)

你并不孤单;这让很多人感到困惑。

这就是我想要的方式。

变量是存储位置。

变量可以存储某种特定类型的东西。

有两种类型:值类型和引用类型。

引用类型变量的值是对该类型对象的引用。

值类型变量的值是该类型的对象。

形式参数是一种变量。

有三种形式参数:值参数,参数参数和输出参数。

当您使用变量作为与value参数对应的参数时,变量的值将复制到与formal参数关联的存储中。如果变量是值类型,则创建该值的副本。如果变量属于引用类型,则会生成引用的副本,并且这两个变量现在引用同一对象。无论哪种方式,都会生成变量值的副本。

当您使用变量作为对应于out或ref参数的参数时,该参数将成为变量的别名。当你说:

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

你所说的是“x和y现在是相同的变量”。它们都引用相同的存储位置

我发现通过将变量的托管地址传递给形式参数,比通过考虑别名实际实现方式更容易理解。

这是清楚的吗?

答案 2 :(得分:4)

列表通过引用传递,因此如果您修改SomeFunction中的列表,也可以修改调用者的列表。

您可以通过创建新列表来创建列表的副本:

var newList = new List<Foo>(oldList);

答案 3 :(得分:2)

您的列表通过引用传递。如果您想传递列表的副本,您可以这样做:

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

如果在克隆中添加/删除元素,则不会修改列表 但两个列表中都会考虑元素本身的修改。

答案 4 :(得分:1)

当您按值传递引用类型(不使用ref或out关键字)时,您可以在此方法中修改此引用类型,并且所有更改都将反映给调用者代码。

要解决您的问题,您可以明确创建副本并将此副本传递给您的函数,或者您可以使用:

list.AsReadOnly();

答案 5 :(得分:0)

传递引用类型时,传递引用。这是一个重要的概念。

如果您传递参考

byref,您直接传递引用(指针)。

byval,您传递了引用(指针)的副本。

引用不是引用的实例。引用与指针类似。

要传递referencetype实例的副本,首先必须自己复制并传递对副本的引用。因此,您将不会修改原始实例。