没有out或ref的方法如何在外部改变变量? C#

时间:2014-04-04 12:11:59

标签: c# pass-by-reference pass-by-value

如何从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

5 个答案:

答案 0 :(得分:6)

您并未在SumElements内更改变量的值 - 它仍然指向之前执行的相同数组。请注意a方法中SumElements的分配方式。

相反,您需要更改数组的内容。该变化在Main中可见,因为它仍然具有对数组的引用。

将变量视为一张纸。在Main中,您有一个名为a的变量,其中包含一个引用 - 一种获取数组的方法。这就像有一张带有街道地址的纸张。这是一个房子的街道地址 - 类似于数组对象。

您正在复制该值(街道地址)并将其用作aSumElements的值。这两张纸是分开的 - 你可以在SumElements中涂鸦,而不会在Main中改变那张纸 - 但是它们从相同的街道地址开始。然后SumElements转到该街道地址,并绘制其中一个窗口。当Main然后转到相同的街道地址时,它也会看到绘制的窗口...因为只有一个房子(数组对象),即使有两个写有相同街道地址的纸片。

有关详细信息,请参阅parameter passingreference types and value types上的文章。

答案 1 :(得分:4)

数组是引用类型。

你没有传递数组的副本,你传递了对它的引用。

这是一个较小的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#中的方法时,默认情况下它是“按值传递”,这意味着您传入的是值的副本,而不是实际的变量本身。

在这种情况下,您传入了参考副本,但该引用引用了一个数组。

因此,该方法有自己对数组的引用,但它仍然使用与“在外部”代码相同的数组。

答案 2 :(得分:1)

由于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)这是了解更多内容的最佳方式

答案 3 :(得分:1)

您的int[] a是一个数组(引用类型)它的地址作为值传递给您的方法SumElements,现在您的方法中的参数a指向内存中的同一个对象。因此,一旦更改了特定索引的值,您就会看到调用者的更改。

您应该看到:Parameter passing in C# by Jon Skeet

答案 4 :(得分:0)

通过引用数据所在的地址来访问每个引用类型(即使未标记为引用参数)。请参阅下面列出了哪些数据类型是引用类型以及哪些是值类型。可以在此处找到非常好的示例和技术详细信息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