按值和引用传递数组
Posted
技术标签:
【中文标题】按值和引用传递数组【英文标题】:Passing Arrays by Value and by Reference 【发布时间】:2012-05-06 16:59:15 【问题描述】:这些是我正在阅读的 c# 书籍中的示例,只是在理解该示例的实际作用时遇到了一些困难,希望得到解释以帮助我进一步了解这里发生的事情。
//creates and initialzes firstArray
int[] firstArray = 1, 2, 3 ;
//Copy the reference in variable firstArray and assign it to firstarraycopy
int[] firstArrayCopy = firstArray;
Console.WriteLine("Test passing firstArray reference by value");
Console.Write("\nContents of firstArray " +
"Before calling FirstDouble:\n\t");
//display contents of firstArray with forloop using counter
for (int i = 0; i < firstArray.Length; i++)
Console.Write("0 ", firstArray[i]);
//pass variable firstArray by value to FirstDouble
FirstDouble(firstArray);
Console.Write("\n\nContents of firstArray after " +
"calling FirstDouble\n\t");
//display contents of firstArray
for (int i = 0; i < firstArray.Length; i++)
Console.Write("0 ", firstArray[i]);
// test whether reference was changed by FirstDouble
if (firstArray == firstArrayCopy)
Console.WriteLine(
"\n\nThe references refer to the same array");
else
Console.WriteLine(
"\n\nThe references refer to different arrays");
//method firstdouble with a parameter array
public static void FirstDouble(int[] array)
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] 11, 12, 13 ;
基本上有代码我想知道的是,这本书说如果数组是按值传递的,而不是原始调用者不会被方法修改(据我了解)。因此,在 FirstDouble 方法结束时,他们尝试将局部变量数组分配给一组新的元素,但这些元素失败了,显示时原始调用者的新值为 2、4、6。
现在我的困惑是方法 FirstDouble 中的 for 循环如何将原始调用者 firstArray 修改为 2,4,6 如果它是按值传递的。我认为该值应保持为 1,2,3。
提前致谢
【问题讨论】:
Value type and reference type problem 的可能重复项 @AlexeiLevenkov 这个在别处覆盖得这么好,我不想关闭那个:( 【参考方案1】:理解这一点的关键是要知道value type and a reference type 之间的区别。
例如,考虑一个典型的值类型,int
。
int a = 1;
int b = a;
a++;
这段代码执行后,a
的值为 2,b
的值为 1
。因为int
是值类型,所以b = a
会复制a
的值。
现在考虑一个类:
MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;
因为类是引用类型,b = a
只分配引用而不是值。所以b
和a
都指的是同一个对象。因此,在a.MyProperty = 2
执行后,b.MyProperty == 2
因为a
和b
指向同一个对象。
考虑到您问题中的代码,数组是引用类型,因此对于此函数:
public static void FirstDouble(int[] array)
变量array
实际上是一个引用,因为int[]
是一个引用类型。所以array
是一个引用,它按值传递。
因此,函数内部对array
的修改实际上应用于array
所引用的int[]
对象。因此,这些修改对引用同一对象的所有引用都是可见的。这包括调用者持有的引用。
现在,如果我们看一下这个函数的实现:
public static void FirstDouble(int[] array)
//double each elements value
for (int i = 0; i < array.Length; i++)
array[i] *= 2;
//create new object and assign its reference to array
array = new int[] 11, 12, 13 ;
还有一个更复杂的问题。 for
循环只是将传递给函数的int[]
的每个元素加倍。这就是调用者看到的修改。第二部分是将新的int[]
对象赋值给局部变量array
。这对调用者是不可见的,因为它所做的只是更改引用array
的目标。由于引用 array
是按值传递的,因此调用者看不到那个新对象。
如果函数是这样声明的:
public static void FirstDouble(ref int[] array)
那么引用 array
将通过引用传递,调用者将在函数返回时看到新创建的对象 11, 12, 13
。
【讨论】:
那么和public static void FirstDouble(ref int[] array)
有什么区别呢?
No 说“变量数组实际上是一个引用”是错误的。这意味着在使用按引用调用术语时,分配给它会改变调用者中的值。继续使用“引用”这个令人困惑的术语,很难谈论 C++ 中的引用或 C# 中的 ref/out
,这就是为什么它得到我的 -1。
@pst,也许这很令人困惑,但它并没有错。引用类型被称为是有原因的。
@svick 措辞错误因为令人困惑。说“x 是一个引用”与说“typeof(x) 是一个引用类型”是不一样的。 变量不是引用。需要将变量的语义和值的语义(变量用来“引用对象”)分开。
@David 在一遍又一遍地阅读您的回复后,我终于明白您在说什么了。这很令人困惑,但感谢您的详细解释,它真的很有帮助【参考方案2】:
术语的用法多么令人困惑!
为了澄清,
对于方法foo(int[] myArray)
,“通过值传递引用(对象)”实际上意味着“传递对象地址(引用)的副本”。这个“副本”的价值,即。 myArray
,最初是原始对象的地址(引用),意味着它指向原始对象。因此,对myArray
所指向的内容的任何更改都会影响到原始对象的内容。
但是,由于myArray
的“值”本身是一个副本,因此对该“值”的任何更改都不会影响原始对象或其内容。
对于foo(ref int[] refArray)
方法,“通过引用传递引用(对象)” 意味着“传递对象的地址(引用)本身(而不是副本)”。这意味着refArray
实际上是对象本身的原始地址,而不是副本。因此,对refArray
的“值”或refArray
指向的内容的任何更改都是对原始对象本身的直接更改。
【讨论】:
【参考方案3】:除非您特别看到ref
或out
,否则所有方法参数都是按值传递的。
数组是引用类型。这意味着您正在按值传递引用。
仅当您为其分配一个新数组时,引用本身才会更改,这就是为什么这些分配不会反映在调用者中的原因。当您取消引用对象(此处为数组)并修改基础值时,您并没有更改变量,只是它指向的内容。即使变量(即它指向的内容)保持不变,调用者也会“看到”这种变化。
【讨论】:
【参考方案4】:为大家提供 .net 开源知识以实现逻辑的想法;
//Sample Code, Illustration;
Method1(params dynamic[] var1)
var1[0]=new dynamic[3] 1,2,3
var1 未指定或不能为 ref ? 一个使用场景是......
//Sample Code, Illustration;
dynamic[] test = new dynamic[];
Method1( ref test,x,x,x,x );
System.Windows.MessageBox.Show( test[2].ToString() );
仅在何时指示 ref,而不是特定于参数; 和数组项的引用;
//result is IndexOutOfBounds;
这只是一个例子,它可以通过返回一个数组并使用如下来完成:
test = Method1( test,... );
而不是:
Method1( ref test,x,x,..., ref test[x], ref test2, ... );
【讨论】:
以上是关于按值和引用传递数组的主要内容,如果未能解决你的问题,请参考以下文章