列表通过ref传递 – 帮我解释一下这个行为
看看下面的程序:
class Test { List<int> myList = new List<int>(); public void TestMethod() { myList.Add(100); myList.Add(50); myList.Add(10); ChangeList(myList); foreach (int i in myList) { Console.WriteLine(i); } } private void ChangeList(List<int> myList) { myList.Sort(); List<int> myList2 = new List<int>(); myList2.Add(3); myList2.Add(4); myList = myList2; } }
我假设myList
会通过ref
,输出会
3 4
该列表确实是“通过ref传递”,但只有sort
function生效。 下面的语句myList = myList2;
没有效果。
所以输出结果实际上是:
10 50 100
你能帮我解释一下这个行为吗? 如果确实myList
不是通过引用 (从myList = myList2
没有生效), myList.Sort()
如何生效?
我甚至假设这个声明不生效,结果是:
100 50 10
你正在传递一个对列表的引用 ,但是你没有通过引用传递列表variables – 所以当你调用ChangeList
时,variables的值 (即引用 – 思考“指针”)被复制 – 并更改为 ChangeList
中 的参数 不会被TestMethod
看到。
尝试:
private void ChangeList(ref List<int> myList) {...} ... ChangeList(ref myList);
然后传递一个对局部variables myRef
(在TestMethod
声明); 现在,如果您在ChangeList
重新分配参数,您也将在 TestMethod
重新分配variables。
最初,它可以用graphics表示如下:
然后,sorting应用myList.Sort();
最后,当你做: myList' = myList2
,你失去了参考,但不是原来的,收集保持sorting。
如果通过引用( ref
)使用myList'
和myList
将会变成相同的(只有一个引用)。
注意:我使用myList'
来表示您在ChangeList
使用的参数(因为您给出了与原始名称相同的名称)
这是一个理解它的简单方法
-
您的列表是在堆上创build的对象。 variables
myList
是对该对象的引用。 -
在C#中,你永远不会传递对象,你可以通过值来传递它们的引用。
-
当您通过
ChangeList
传递的引用访问列表对象时(例如,在sorting时),原始列表会更改。 -
ChangeList
方法的赋值是由引用的值决定的,因此不会对原始列表进行更改(仍然在堆上,但是不再在方法variables上引用)。
这个链接将帮助你理解C#中的引用。 基本上,当一个引用types的对象被值传递给一个方法时,只有该对象上可用的方法才能修改该对象的内容。
例如,List.sort()方法更改列表内容,但是如果将某个其他对象分配给相同的variables,则该分配对于该方法是本地的。 这就是为什么myList保持不变。
如果我们通过使用ref关键字来传递引用types的对象,那么我们可以将一些其他对象分配给同一个variables,并且改变整个对象本身。
C#只是通过值传递一个浅拷贝,除非有问题的对象执行ICloneable
(显然List
类没有)。
这意味着它复制List
本身,但对列表中的对象的引用保持不变; 也就是说,指针继续引用与原始List
相同的对象。
如果您更改新List
引用的值的值,则也会更改原始List
(因为它引用的是相同的对象)。 但是,您然后将myList
完全引用的内容更改为新的List
,现在只有原始List
引用这些整数。
阅读“传递参数”这篇MSDN文章中的“ 传递引用types参数”部分以获取更多信息。
“如何克隆C#中的通用列表”从StackOverflow谈到如何制作一个列表的深层副本。
虽然我同意以上所有人的说法。 我对这个代码有不同的看法。 基本上你将新列表分配给本地variablesmyList而不是全局。 如果将ChangeList(List myList)的签名更改为private void ChangeList(),则会看到3,4的输出。
这是我的推理…即使列表通过引用传递,认为它通过值传递指针variables当您调用ChangeList(myList)您传递指针(全球)myList。 现在这个存储在(本地)myListvariables中。 所以现在你的(本地)myList和(全局)myList指向相同的列表。 现在你做一个sorting=>它的工作原因是(本地)myList引用原始(全局)myList接下来你创build一个新的列表,并指定你的(本地)myList指针。 但只要函数退出(本地)myListvariables被销毁。 HTH
class Test { List<int> myList = new List<int>(); public void TestMethod() { myList.Add(100); myList.Add(50); myList.Add(10); ChangeList(); foreach (int i in myList) { Console.WriteLine(i); } } private void ChangeList() { myList.Sort(); List<int> myList2 = new List<int>(); myList2.Add(3); myList2.Add(4); myList = myList2; } }
使用ref
关键字。
在这里看明确的参考来理解传递参数。
具体来说,看看这个 ,了解代码的行为。
编辑: Sort
工作在同一个引用(即通过值),因此,这些值是有序的。 然而,分配一个新的实例参数将无法正常工作,因为参数是通过值传递,除非你把ref
。
把ref
放在你的案例中,你可以改变指向List
的新实例的引用。 没有ref
,你可以在现有的参数上工作,但不能指向其他的东西。