列表是按值传递的吗?

Posted

技术标签:

【中文标题】列表是按值传递的吗?【英文标题】:Are ILists passed by value? 【发布时间】:2011-01-20 10:53:57 【问题描述】:

除非您在参数上使用 ref 或 out 关键字,否则在 c# 中将 Value Type 参数传递给函数是按值的。但这是否也适用于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

【问题讨论】:

感谢大家的快速回复!就像我预期的那样。只是有片刻的不确定性.. 如果你想做一些聪明的事情,你可以创建一个自己的列表类,通过复制隐式转换为 IList。我能看到的唯一好处是,它理论上可以防止您在传递集合时“忘记”制作副本。 不-我不想那样做.. 采用 IEnumerable 的 List 构造函数似乎很聪明。我只需要.. 别怪你。通常,我使用“聪明”作为“不要这样做”的同义词。 【参考方案1】:

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

如果您想复制列表本身,List&lt;T&gt; 有一个 handy constructor,它需要一个 IEnumerable&lt;T&gt;

【讨论】:

此外,如果您更改函数主体内的引用,则调用者将看不到此更改。来自我的 +1。 @Aggelos:没错。这是按值传递的属性。【参考方案2】:

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

这是我喜欢的想法。

变量是一个存储位置。

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

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

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

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

形参是一种变量。

形式参数分为三种:值参数、引用参数和输出参数。

当您使用变量作为与值形参对应的实参时,该变量的值将被复制到与形参关联的存储中。如果变量是值类型,则制作该值的副本。如果变量是引用类型,则复制引用,两个变量现在引用同一个对象。无论哪种方式,都会制作变量值的副本。

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

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

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

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

清楚吗?

【讨论】:

【参考方案3】:

列表是通过引用传递的,所以如果你在 SomeFunction 中修改列表,你也会为调用者修改列表。

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

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

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

+1 解释:...but the modifications of the elements themselves will be taken into account in both lists.【参考方案5】:

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

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

list.AsReadOnly();

【讨论】:

【参考方案6】:

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

如果你传递了一个引用

byref,你直接传递 reference(指针)。

byval,你传递了 reference(指针)的副本。

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

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

【讨论】:

以上是关于列表是按值传递的吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python 的布尔值是按值传递的吗?

C++中的指针是按值传递的吗?

java中的参数传递是按引用传递还是按值传递

JavaScript 是按引用传递还是按值传递? [复制]

JavaScript 是按引用传递还是按值传递语言?

js传参是按值传递还是按引用传递?