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
The list is确实“通过 ref 传递”,但只有 >sort
函数生效。以下语句 myList = myList2;
无效。
所以输出实际上是:
10
50
100
你能帮我解释一下这个行为吗?如果 myList
确实不是passed-by-ref(因为 myList = myList2
没有生效),那么 myList 如何.Sort()
生效吗?
我什至假设该声明不会生效,并且输出为:
100
50
10
Take a look at the following program:
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;
}
}
I assumed myList
would have passed by ref
, and the output would
3
4
The list is indeed "passed by ref", but only the sort
function takes effect. The following statement myList = myList2;
has no effect.
So the output is in fact:
10
50
100
Can you help me explain this behavior? If indeed myList
is not passed-by-ref (as it appears from myList = myList2
not taking effect), how does myList.Sort()
take effect?
I was assuming even that statement to not take effect and the output to be:
100
50
10
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您正在传递对列表的引用,但您没有通过引用传递列表变量 - 因此,当您调用
ChangeList 时
变量的值(即引用 - 认为“指针”)被复制 - 并更改为ChangeList< 内的参数值 /code> TestMethod 看不到。
try:
然后传递对本地变量的引用
myRef
(如TestMethod
中声明的);现在,如果您在ChangeList
内重新分配参数,您也会在TestMethod
内重新分配变量内部。You are passing a reference to the list, but your aren't passing the list variable by reference - so when you call
ChangeList
the value of the variable (i.e. the reference - think "pointer") is copied - and changes to the value of the parameter insideChangeList
aren't seen byTestMethod
.try:
This then passes a reference to the local-variable
myRef
(as declared inTestMethod
); now, if you reassign the parameter insideChangeList
you are also reassigning the variable insideTestMethod
.这是一种简单的理解方法
您的列表是在堆上创建的对象。变量
myList
是一个对该对象的引用。
在 C# 中,您从不传递对象,而是按值传递它们的引用。
ChangeList
(例如,在排序时)原始列表会发生更改。对
ChangeList
方法的赋值是对引用的值进行的,因此不会对原始列表进行任何更改(仍在堆上,但不再在方法变量上引用)。< /p>Here is an easy way to understand it
Your List is an object created on heap. The variable
myList
is areference to that object.
In C# you never pass objects, you pass their references by value.
When you access the list object via the passed reference in
ChangeList
(while sorting, for example) the original list is changed.The assignment on the
ChangeList
method is made to the value of the reference, hence no changes are done to the original list (still on the heap but not referenced on the method variable anymore).此链接将帮助您理解 C# 中的引用传递。
基本上,当引用类型的对象按值传递给方法时,只有该对象上可用的方法才能修改对象的内容。
例如,List.sort() 方法更改列表内容,但如果您将某个其他对象分配给同一变量,则该分配对于该方法来说是本地的。这就是 myList 保持不变的原因。
如果我们使用 ref 关键字传递引用类型的对象,那么我们可以将一些其他对象分配给同一个变量,这会改变整个对象本身。
(编辑:this 是上面链接的文档的更新版本。)
This link will help you in understanding pass by reference in C#.
Basically,when an object of reference type is passed by value to an method, only methods which are available on that object can modify the contents of object.
For example List.sort() method changes List contents but if you assign some other object to same variable, that assignment is local to that method. That is why myList remains unchanged.
If we pass object of reference type by using ref keyword then we can assign some other object to same variable and that changes entire object itself.
(Edit: this is the updated version of the documentation linked above.)
C# 在按值传递时只会执行浅复制,除非相关对象执行 ICloneable(显然
List
类不会执行)。这意味着它复制
List
本身,但对列表内对象的引用保持不变;也就是说,指针继续引用与原始 List 相同的对象。如果您更改新
List
引用的内容的值,您也会更改原始List
(因为它引用相同的对象)。但是,您随后将myList
引用的内容完全更改为新的List
,现在只有原始List
引用这些整数。阅读 这篇关于“传递参数”的 MSDN 文章了解更多信息。
“如何在 C# 中克隆通用列表” 来自 StackOverflow 的讨论如何制作列表的深层副本。
C# just does a shallow copy when it passes by value unless the object in question executes
ICloneable
(which apparently theList
class does not).What this means is that it copies the
List
itself, but the references to the objects inside the list remain the same; that is, the pointers continue to reference the same objects as the originalList
.If you change the values of the things your new
List
references, you change the originalList
also (since it is referencing the same objects). However, you then change whatmyList
references entirely, to a newList
, and now only the originalList
is referencing those integers.Read the Passing Reference-Type Parameters section from this MSDN article on "Passing Parameters" for more information.
"How do I Clone a Generic List in C#" from StackOverflow talks about how to make a deep copy of a List.
虽然我同意上面大家所说的。我对这段代码有不同的看法。
基本上,您将新列表分配给局部变量 myList 而不是全局变量。
如果将 ChangeList(List myList) 的签名更改为 private void ChangeList(),您将看到 3, 4 的输出。
这是我的推理...
即使列表是通过引用传递的,也可以将其视为按值传递指针变量
当您调用 ChangeList(myList) 时,您将指针传递给(全局)myList。现在它存储在(本地)myList 变量中。所以现在你的 (local)myList 和 (global)myList 指向同一个列表。
现在你进行排序 =>它起作用是因为 (local)myList 引用原始 (global)myList
接下来,您创建一个新列表并将指针分配给您的(本地)myList。但一旦函数退出,(本地)myList 变量就会被销毁。
华泰
While I agree with what everyone has said above. I have a different take on this code.
Basically you're assigning the new list to the local variable myList not the global.
if you change the signature of ChangeList(List myList) to private void ChangeList() you'll see the output of 3, 4.
Here's my reasoning...
Even though list is passed by reference, think of it as passing a pointer variable by value
When you call ChangeList(myList) you're passing the pointer to (Global)myList. Now this is stored in the (local)myList variable. So now your (local)myList and (global)myList are pointing to the same list.
Now you do a sort => it works because (local)myList is referencing the original (global)myList
Next you create a new list and assign the pointer to that your (local)myList. But as soon as the function exits the (local)myList variable is destroyed.
HTH
使用
ref
关键字。查看此处的权威参考以了解传递参数。
具体来说,请查看此,了解代码的行为。
编辑:
Sort
适用于相同的引用(按值传递),因此值是有序的。但是,为参数分配新实例将不起作用,因为参数是按值传递的,除非您放置ref
。通过放置
ref
,您可以将指针更改为对您的情况下的List
新实例的引用。如果没有ref
,您可以处理现有参数,但无法使其指向其他参数。Use the
ref
keyword.Look at the definitive reference here to understand passing parameters.
To be specific, look at this, to understand the behavior of the code.
EDIT:
Sort
works on the same reference (that is passed by value) and hence the values are ordered. However, assigning a new instance to the parameter won't work because parameter is passed by value, unless you putref
.Putting
ref
lets you change the pointer to the reference to a new instance ofList
in your case. Withoutref
, you can work on the existing parameter, but can't make it point to something else.为引用类型的对象分配了两部分内存。一种在栈中,一种在堆中。堆栈中的部分(也称为指针)包含对堆中部分的引用 - 实际值存储在堆中。
当不使用 ref 关键字时,仅创建堆栈中部分的副本并将其传递给方法 - 对堆中相同部分的引用。因此,如果您更改堆部分中的某些内容,这些更改将保留。如果您更改复制的指针 - 通过将其指定为引用堆中的其他位置 - 它不会影响方法外部的原始指针。
There are two parts of memory allocated for an object of reference type. One in stack and one in heap. The part in stack (aka a pointer) contains reference to the part in heap - where the actual values are stored.
When ref keyword is not use, just a copy of part in stack is created and passed to the method - reference to same part in heap. Therefore if you change something in heap part, those change will stayed. If you change the copied pointer - by assign it to refer to other place in heap - it will not affect to origin pointer outside of the method.
最初,它可以用图形表示如下:
然后,应用排序
myList.Sort() ;
最后,当您执行以下操作时:
myList' = myList2
,您丢失了其中一个参考,但不是原始的,并且集合保持排序。如果您通过引用使用 (
ref
),则myList'
和myList
将变得相同(只有一个引用)。注意:我使用
myList'
来表示您在中使用的参数>ChangeList
(因为您提供的名称与原始名称相同)Initially, it can be represented graphically as follow:
Then, the sort is applied
myList.Sort();
Finally, when you did:
myList' = myList2
, you lost the one of the reference but not the original and the collection stayed sorted.If you use by reference (
ref
) thenmyList'
andmyList
will become the same (only one reference).Note: I use
myList'
to represent the parameter that you use inChangeList
(because you gave the same name as the original)