按引用传递 - 没有 out 或 ref 的方法如何在自身外部更改变量?C#.
本文关键字:外部 改变 变量 out 没有 ref 方法 按引用传递 | 更新日期: 2023-09-27 17:56:32
如何从方法内部更改数组a
的值SumElemtnts
?是因为它是一种静态方法吗?因为该方法只返回变量sum
,没有 ref 或 out。
class Program
{
public static int SumElements(int[] a)
{
int[] a2 = a;
int sum = 0;
for (int i = 0; i < a2.Length; i++)
{
int temp = a2[i] * 10;
a2[i] = temp;
sum += temp;
}
a[a2.Length - 2] = sum;
return sum;
}
public static void Main(string[] args)
{
int[] a = { 1, 2, 3 };
int sum = SumElements(a);
Console.Write("Sum = " + sum + ", ");
for (int i = 0; i < a.Length; i++)
{
Console.Write(a[i] + " ");
}
}
}
结果是:
总和 = 60, 10 60 30
您没有更改SumElements
变量的值 - 它仍然引用与之前相同的数组。请注意,SumElements
方法中没有要a
的赋值。
相反,您正在更改数组的内容。这种变化在Main
中是可见的,因为它仍然有对数组的引用。
将变量想象成一张纸。在Main
中,你有一个名为a
的变量,它包含一个引用 - 一种到达数组的方法。这就像有一张写有街道地址的纸。这是房子的街道地址 - 类似于数组对象。
您正在复制该值(街道地址)并将其用作SumElements
中的a
值。这两张纸是分开的——你可以在SumElements
的那张纸上涂鸦,这不会改变Main
纸——但它们以相同的街道地址开始。 然后SumElements
去那个街道地址,粉刷其中一扇窗户。当Main
走到同一个街道地址时,它也看到了彩绘的窗户......因为只有一个房子(数组对象),即使有两张纸上写着相同的街道地址。
有关更多详细信息,请参阅我关于参数传递和引用类型以及值类型的文章。
数组是一种引用类型。
您不是在传入数组的副本,而是在传入对它的引用。
下面是一个较小的 LINQPad 程序,用于演示:
void Main()
{
var a = new[] { 1, 2, 3 };
Test(a);
a.Dump();
}
public static void Test(int[] arr)
{
arr[1] = 15;
}
输出:
1
15
3
更长的说明:在 C# 中将值传递给方法时,默认情况下为"按值传递",这意味着你传入的是值的副本,而不是实际变量本身。
在本例中,您正在传入引用的副本,但引用引用的是数组。
因此,该方法对数组有自己的引用,但它仍然使用与"外部"代码相同的数组。
你的int[] a
是一个数组(引用类型),它的地址作为值传递给你的方法SumElements
,现在方法中的参数a
指向内存中的同一对象。因此,一旦您更改了特定索引的值,您就会在调用方中看到更改。
您应该看到:Jon Skeet 在 C# 中的参数传递
原因很简单,array is reference type
所以你正在更改数组的内容
From MSDN:
下面的示例演示如何按值将引用类型参数 arr 传递给方法 Change。由于参数是对 arr 的引用,因此可以更改数组元素的值。但是,尝试将参数重新分配给不同的内存位置仅适用于方法内部,不会影响原始变量 arr。C#
class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
static void Main()
{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr [0]);
Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: 888
*/
尝试阅读Passing Reference-Type Parameters (C# Programming Guide)
这是了解更多发生的事情的最佳方式
每个引用类型都是通过引用数据所在的地址来访问的(即使未标记为引用参数)。请参阅下面的列表,了解哪些数据类型是引用类型,哪些是值类型。非常好的示例和技术细节可以在这里找到 http://www.albahari.com/valuevsreftypes.aspx
值类型值类型包括:
All numeric data types
Boolean, Char, and Date
All structures, even if their members are reference types
Enumerations
引用类型引用类型包括:
String
All arrays, even if their elements are value types
Class types, such as Form
Delegates