列表通过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传递”,但只有sortfunction生效。 下面的语句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的对象。 variablesmyList是对该对象的引用。

  • 在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 ,你可以在现有的参数上工作,但不能指向其他的东西。