为什么在没有引用的情况下传递列表到函数时,其行为就像使用引用传递一样?
如果我没有犯下严重的错误,这种行为对我来说很奇怪。我将在下面发布一个示例代码,而不是解释,请告诉我为什么我得到输出 x 而不是 y。
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(List<int> l)
{
l.Add(4);
l.Add(5);
}
我假设输出应该是 3。但是我得到的输出是 5。我知道如果我这样做,输出可以是 5:
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(ref l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(ref List<int> l)
{
l.Add(4);
l.Add(5);
}
If I did not get this terribly wrong, this behaviour is strange for me. Rather than explaining, I'll post a sample code below and please tell me why does I get output x and not y.
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(List<int> l)
{
l.Add(4);
l.Add(5);
}
Output should, I assume would be 3. But I get the output as 5. I understand the output can be 5 if I do this:
private void button1_Click(object sender, EventArgs e)
{
List<int> l = new List<int>() { 1, 2, 3 };
Fuss(ref l);
MessageBox.Show(l.Count.ToString()); // output is 5
}
private void Fuss(ref List<int> l)
{
l.Add(4);
l.Add(5);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
它的行为不像是通过引用传递的。
尝试一下。你注意到其中的区别了吗?
如果您在没有引用的情况下传递列表(或任何引用类型),则只能更改列表的内容(因为正如其他人所说,您正在传递对堆上对象的引用,从而更改相同的“内存”)。
但是您不能更改“list”,“list”是一个指向 List 类型的对象的变量。如果您通过引用传递“列表”(以使其指向其他位置),则只能更改“列表”。您将获得引用的副本,如果更改,则只能在您的方法内观察到该副本。
It does not act like its passed by ref.
Try it. Do you notice the difference?
You can only change the contents of list (or any reference type) if you pass it without a ref (because as others have said, you are passing a reference to the object on the heap and thus change the same "memory").
However you cannot change "list", "list" is a variable that points to an object of type List. You can only change "list" if you pass it by reference (to make it point somewhere else). You get a copy of the reference, which if changed, can only be observed inside your method.
在 C# 中,参数按值传递,除非它们用
ref
或out
修饰符标记。对于引用类型,这意味着引用是按值传递的。因此,在Fuss
中,l
引用List
与其调用者相同的实例。因此,对此List
实例的任何修改都将被调用者看到。现在,如果您使用
ref
或out
标记参数l
,则该参数将通过引用传递。这意味着在Fuss
中,l
是存储位置的别名,用作调用该方法的参数。需要明确的是:在
Fuss
中,由 Now 调用,
l
是list
的别名。特别是,如果您将List
的新实例分配给l
,调用者将看到分配给变量list
的新实例以及。特别是,如果您说then,调用者现在将看到一个包含一个元素的列表。但是,如果您说
并调用
,那么调用者仍然会看到
list
具有三个元素。清除?
Parameters are passed by value in C# unless they are marked with the
ref
orout
modifiers. For reference types, this means that the reference is passed by value. Therefore, inFuss
,l
is referring to the same instance ofList<int>
as its caller. Therefore, any modifications to this instance ofList<int>
will be seen by the caller.Now, if you mark the parameter
l
withref
orout
, then the parameter is passed by reference. What this means is that inFuss
,l
is an alias for storage location used as a parameter to invoke the method. To be clear:called by
Now, in
Fuss
,l
is an alias forlist
. In particular, if you assign a new instance ofList<int>
tol
, the caller will see that new instance assigned to the variablelist
as well. In particular, if you saythen the caller will now see a list with one element. But if you say
and call by
then the caller will still see
list
as having three elements.Clear?
ByRef 和 ByVal 仅适用于值类型,不适用于引用类型,引用类型始终像“byref”一样传递。
如果您需要谨慎地修改列表,请使用“.ToList()”函数,您将获得列表的克隆。
请记住,如果您的列表包含引用类型,则“新”列表包含指向与原始列表相同的对象的指针。
ByRef and ByVal only apply to value types, not to reference types, which are always passed as though they were "byref".
If you need to modify a list discreetly, use the ".ToList()" function, and you'll get a clone of your list.
Keep in mind that if your list contains reference types, your "new" list contains pointers to the same objects that your original list did.
列表已经是引用类型,因此当您将它们传递给方法时,您正在传递引用。任何
Add
调用都会影响调用者中的列表。通过
ref
传递List
的行为本质上类似于向该列表传递双指针。这是一个例子:Lists are already reference types, so when you pass them to a method, you are passing a reference. Any
Add
calls will affect the list in the caller.Passing a
List<T>
byref
behaves essentially like passing a double-pointer to that list. Here's an illustration:“List”类型的变量、参数或字段或任何其他引用类型实际上并不保存列表(或任何其他类的对象)。相反,它会保存类似“对象 ID #29115”的内容(当然,不是这样一个实际的字符串,而是本质上意味着这一点的位组合)。在其他地方,系统将有一个称为堆的索引对象集合;如果 List 类型的某个变量保存“对象 ID #29115”,则堆中的对象 #29115 将是 List 的实例或从中派生的某种类型。
如果 MyFoo 是 List 类型的变量,像 'MyFoo.Add("George")' 这样的语句实际上不会改变 MyFoo;相反,它的意思是“检查存储在 MyFoo 中的对象 ID,并调用存储在其中的对象的“Add”方法。如果 MyFoo 在执行语句之前持有“Object ID #19533”,则之后它将继续这样做,但是 Object ID #19533 将调用其 Add 方法(可能会更改该对象),相反,像“MyFoo = MyBar”这样的语句将使 MyFoo 拥有与 MyBar 相同的对象 ID,但实际上不会这样做。如果 MyBar 在该语句之前持有“Object ID #59212”,则在该语句之后,MyFoo 也将持有“ObjectId #59212”,对象 ID #19533 和对象 ID#59212 都不会发生任何情况。 。
A variable, parameter, or field of type "List", or any other reference type, doesn't actually hold a list (or object of any other class). Instead, it will hold something like "Object ID #29115" (not such an actual string, of course, but a combination of bits which means essentially that). Elsewhere, the system will have an indexed collection of objects called the heap; if some variable of type List holds "Object ID #29115", then object #29115 in the heap will be an instance of List or some type derived therefrom.
If MyFoo is a variable of type List, a statement like 'MyFoo.Add("George")' won't actually change MyFoo; instead, it means "Examine the object ID stored in MyFoo, and invoke the "Add" method of the object stored therein. If MyFoo held "Object ID #19533" before the statement executed, it will continue to do so afterward, but Object ID #19533 will have had its Add method invoked (probably altering that object). Conversely, a statement like "MyFoo = MyBar" will make MyFoo hold the same object-id as MyBar, but won't actually do anything to the objects in question. If MyBar held "Object ID #59212" before the statement, then after the statement, MyFoo will also hold "ObjectId #59212". Nothing will have happened to object ID #19533, nor object ID#59212.
对于像 List 这样的引用类型,ref 和 non-ref 之间的区别不在于是否传递引用(这种情况总是发生),而是该引用是否可以更改。尝试以下操作
,您将看到计数为 2,因为该函数不仅操作原始列表,还操作引用本身。
The difference between ref and non-ref for reference types like List is not whether you pass a reference (that happens always), but whether that reference can be changed. Try the following
and you'll see the count is 2, because the function not only manipulated the original list but the reference itself.
只有 int、double 等基本类型是按值传递的。
复杂类型(如列表)通过引用传递(确切地说,这是按值传递指针)。
Only primitive types like int, double etc. are passed by value.
Complex types (like list) are passed via reference (which is a passing pointer by value, to be exact).
让我们解释一下简单:)
lets explain it Easy :)
if it seems confusing i think you should have a deep understanding of what a reference is