按引用传递 - 没有 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

按引用传递 - 没有 out 或 ref 的方法如何在自身外部更改变量?C#.

您没有更改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