在main中我声明了一个本地int []数组(int [] nums)。我没有通过引用传递它。 但是当我打印局部数组的值时,我得到每个元素的平方值。 这是什么原因?
delegate void tsquare(int[] a);
static void Main()
{
int[] nums = { 1, 2, 3 };
tsquare sqr = new tsquare(SomeClass.Square);
sqr(nums);
foreach (int intvals in nums)
{
Console.WriteLine(intvals);
}
}
class SomeClass
{
public static void Square(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
}
更新
我对所有人的批评。我认为是int [] {Array}是一个值类型,而委托完成了 关于它的一些技巧。现在从你的回答中,我理解Array是引用类型。
答案 0 :(得分:3)
这里有两个概念。
让我们先解决第二个问题。
按值传递内容意味着您为该方法提供了该值的副本,并且可以随意更改该值,而不会将这些更改泄漏回调用该方法的代码中。
例如,这个:
Int32 x = 10;
SomeMethod(x); // pass by value
在这种情况下,在调用返回之后,x将不会是10以外的任何东西,因为无论SomeMethod对其值的副本做了什么,它只会做到它自己的值。
然而,通过引用传递意味着我们并没有真正给出该方法自己的值,而是我们给它在我们自己的值所在的内存中的位置,因此方法对该值的任何作用将是反映回我们的代码,因为实际上,只有一个价值在起作用。
所以这个:
Int32 x = 10;
SomeMethod(ref x); // pass by reference
在这种情况下,x可能在SomeMethod返回后保持的值不同于调用之前的值。
所以这是通过价值而不是通过参考传递。
现在要混淆水域。还有另一个概念,参考类型与价值类型,许多人混淆。你的问题暗示你也对这个问题感到困惑,如果你不这样做,我表示道歉。
参考类型实际上是一个由两部分组成的东西。它是一个参考,它是参考引用的任何内容。想想你知道地址的房子。你在一张纸上写下这个地址实际上并没有将整个房子放在那张纸上,而是你对你纸上的那个房子有一个“参考”。
.NET中的引用类型是一回事。在内存中的某处,有一个对象,它是一组值,组合在一起。存储在变量中的此对象的地址。这个变量被声明为一个引用类型的类型,它允许这个由两部分组成的交易。
引用类型的好处是你可能有很多对同一个实际对象的引用,所以即使你复制引用,你仍然只有一个对象在内存中。
编辑:关于问题,数组是引用类型。这意味着您的变量只保存实际数组的地址,并且该数组对象位于内存中的其他位置。
值类型是一回事,整个值是“值类型”的一部分,当你复制它时,你会制作不同的副本
以下是值类型的示例:
struct SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // value type, so y is now a copy of x
y.Value = 20; // x.Value is still 10
但是,对于引用类型,您不是要复制它引用的对象,而是只复制引用。可以把它想象成将那个房子的地址复制到第二张纸上。你仍然只有一所房子。
因此,只需将SomeType的类型更改为引用类型(将struct
更改为class
):
class SomeType
{
public Int32 Value;
}
SomeType x = new SomeType;
x.Value = 10;
SomeType y = x; // reference type, so y now refers to the same object x refers to
y.Value = 20; // now x.Value is also 20, since x and y refer to the same object
现在最后的事情;按值传递引用类型。
采取这种方法:
public void Test(SomeType t)
{
t.Value = 25;
}
鉴于我们上面的SomeType的类版本,我们这里有一个采用引用类型参数的方法,但它将它作为值传递。
这意味着Test无法更改t
以完全引用另一个对象,并使该更改泄漏回调用代码。把这想象成打电话给朋友,给他你在纸上的地址。无论你的朋友在那所房子里做什么,你在纸上的地址都不会改变。
但是,该方法可以自由修改对象的内容引用。在那个房子/朋友场景中,你的朋友可以自由地去那个房子,并重新安排家具。因为只有一个房子在玩,如果你重新安排它后去那个房子,你会看到他的变化。
如果更改方法以通过引用传递引用类型,则不仅该方法可以自由重新排列所引用对象的内容,而且该方法也可以使用一个完全新的对象替换该对象,并且将更改反映回调用代码。基本上,你的朋友可以告诉你“从现在开始,使用这个我会读给你的新地址而不是旧地址,完全忘掉旧地址。”
答案 1 :(得分:2)
在C#中,默认情况下所有参数都按值传递。 C#中有两种类型,即值和引用类型。
作为参数传递给函数时的引用类型变量仍将按值传递;也就是说,如果函数更改了该变量引用的对象,则在函数完成后,传入的变量仍将引用与在同一上下文中调用函数之前相同的对象(包括null)。
但是,如果在声明函数参数时使用ref
修饰符,则函数可能会更改调用者上下文中变量引用的对象。
对于值类型,这更直接,但它是相同的概念。请记住,int[]
是引用类型(与所有数组一样)。
在传递一些int数组时考虑这些函数的不同之处:
public static void Square1(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square2(int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
public static void Square3(ref int[] array)
{
array = {10, 20, 30};
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i] * array[i];
}
}
答案 2 :(得分:2)
答案 3 :(得分:2)
其他大多数答案都是正确的,但我认为术语令人困惑并需要解释。默认情况下,您可以说C#中的所有参数都是按值传递的,这意味着变量的内容将复制到方法变量中。这对于值类型的变量是直观的,但诀窍在于记住作为引用类型(包括数组)的变量实际上是指针。传入时,指针包含的内存位置将复制到该方法中。
应用 ref 修饰符时,该方法从调用者获取实际变量。在大多数情况下,行为是相同的,但请考虑以下内容:
public void DoesNothing(int[] nums)
{
nums = new []{1, 2, 3, 4};
}
在DoesNothing中,我们实例化一个新的int数组并将其分配给nums。当方法退出时,调用者看不到赋值,因为该方法正在操作传入的引用(指针)的副本。
public void DoesSomething(ref int[] nums)
{
nums = new []{1, 2, 3, 4};
}
使用 ref 关键字,该方法基本上可以从调用者那里伸出并影响原始变量本身。
要实现您最初想要的内容,您可以创建一个新数组并将其返回,或者在调用者中使用Array.CopyTo()。
答案 4 :(得分:1)
你没有通过引用传递它。数组是按值传递的,但.NET中的数组是引用类型,因此您传入对数组的引用,这就是您看到值的平方值的原因。
答案 5 :(得分:0)
数组是对象,通过引用传递。 Ints是结构并按值传递(除非您在方法签名中使用ref
关键字,根据评论中的挑剔的人)(谁是正确的)(但挑剔)。
答案 6 :(得分:0)
阅读以下SO问题 - 它解释了传值和传递参考之间的差异。接受的答案中有一个关于该主题的好文章的链接,可以帮助您理解差异。
what is different between Passing by value and Passing by reference using C#