IList是否按价值传递?
将参数Value Type传递给c#中的函数是通过值,除非您在参数上使用ref或out关键字。但是这也适用于Reference Types?IList是否按价值传递?
具体而言,我有一个功能,需要一个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
}
所有参数是按值传递,除非你明确地使用ref
或out
。但是,当您传递引用类型的实例时,您会按值传递引用。即引用本身被复制,但由于它仍然指向同一个实例,所以仍然可以通过此引用修改实例。即该实例未被复制。参考是。
如果你想复制一份清单本身,List<T>
有一个handy constructor,需要IEnumerable<T>
。
此外,如果您更改函数体内的引用,则此更改在调用方中将不可见。从我+1。 – 2010-02-24 10:02:54
@Aggelos:的确如此。这是通过价值传递的特性。 – 2010-02-24 10:17:23
该列表通过引用传递,因此如果您在SomeFunction中修改列表,则也会修改调用者的列表。
您可以通过创建一个新创建列表的副本:
var newList = new List<Foo>(oldList);
您的列表通过引用传递。如果你想通过列表的副本,你可以这样做:
IList<Foo> clone = new List<Foo>(list);
如果添加/删除克隆的元素不会改变显示 但要素的修改自己会考虑在这两个名单。
+1的解释:'...但这些元素本身的修改将在这两个列表中考虑到.' – 2016-05-15 06:10:43
当您通过值传递引用类型(不带ref或out关键字)时,您可以在此方法内修改此引用类型,并且所有更改都会反映给调用者的代码。
解决你的问题,你可以明确地创建一个副本,这个副本传递给你的函数,或者你可以使用:
list.AsReadOnly();
你并不孤单;这让很多人感到困惑。
以下是我喜欢的方式。
变量是一个存储位置。
变量可以存储某种特定类型的东西。
有两种类型:值类型和引用类型。
引用类型变量的值是对该类型对象的引用。
值类型变量的值是该类型的对象。
形式参数是一种变量。
形式参数有三种:值参数,参考参数和输出参数。
当您将变量用作参数值对应的参数时,该变量的值将被复制到与形式参数关联的存储中。如果该变量是值类型的,则创建该值的一个副本。如果变量是引用类型,则引用的副本被创建,并且这两个变量现在引用同一个对象。无论哪种方式,都会创建一个变量值的副本。
当您使用变量作为参数对应于out或ref参数时,该参数将成为变量的别名。当你说:
void M(ref int x) { ...}
...
int y = 123;
M(ref y);
你说的话是“x和y现在同一变量”。他们都提到相同的存储位置。
我发现比理解别名是如何实际实现的更容易理解 - 通过将变量的托管地址传递给形式参数。
这是明确的吗?
超级清晰!谢谢 :-) – stiank81 2010-02-24 21:13:52
Thx为快速回复的人!就像我预料的那样。只是有一个不确定的时刻.. – stiank81 2010-02-24 09:21:47
如果你想做一些聪明的事情,你可以做一个你自己的列表类,通过复制隐式投给IList。我能看到的唯一好处是,它在理论上可以防止您在传递集合时“忘记”复制副本。 – kyoryu 2010-02-24 09:43:32
不 - 我不想那样做。IEnumerable的List构造函数看起来像它一样聪明。所有我需要.. – stiank81 2010-02-24 09:45:52