将数组作为参数传递

5

如果我们在方法中修改作为参数传递的数组的内容,修改会在参数的副本上进行,而不是在原始参数上进行,因此结果不可见。

当我们调用具有引用类型参数的方法时,会发生什么过程?

下面是我想要询问的代码示例:

      using System;

namespace Value_Refrence_Type
{
    class Program
    {
        public static void Main()
        {
            int[] callingarray = { 22, 200, 25485 };
            abc(callingarray);
            Console.WriteLine("This is callingarray");
            foreach (int element in callingarray)
                Console.WriteLine(element);
        }



        //method parameter
        static void abc(int[] calledarray)
        {
            Console.WriteLine("Method Called--------");
            foreach (int element in calledarray)
                Console.WriteLine(element);

            //Here on changing the value of elements of calledarray does't afftect the value of element of callingarray
            //if both refrences to same memory location then the value needs to change, which is not happening here
            calledarray = new int[] {55, 54, 65};
            foreach (int element in calledarray)
                Console.WriteLine(element);
        }

    }
}

8
@nicomp 数组或者其它对象在 C# 中并不是传递引用的形式。所有对象都默认以值传递。如果要传递引用,需要使用 "ref" 或 "out" 关键字。您好像在混淆引用类型和参数传递的概念。 - InBetween
6
@nicomp,你把按值传递的引用类型的行为与按引用传递参数混淆了。当按引用传递参数时,你可以将新数组分配给该参数,这将更改调用处的变量,而在我们讨论的代码中显然不是这种情况。再次强调,很简单,要按引用传递参数,你需要使用提供的关键字refout,否则它将被按值传递。如果你仍然不信服,我建议你阅读C#规范的相关部分。 - InBetween
3
很有趣,你指出了我的答案。我看到你还没有被说服,所以我会引用MSDN的内容:"(...) 要通过引用传递参数,请使用ref或out关键字。(...)"。 - InBetween
9
我看到一个参数以值的方式传递,这意味着变量被复制。因为变量持有一个引用类型,所以引用被复制并指向同一个对象。但是,这并不是通过引用传递参数。通过引用传递参数需要使用 "ref" 关键字,并允许你在调用点更改原始变量的值,也就是说,我可以说 a = null ,当方法返回时,调用点的变量将是 null。在你的示例中尝试一下,看看它是如何工作的。再次阅读我之前回答中的链接。 - InBetween
7
@RobertHarvey 在那些真正了解幕后情况的人之间交谈时,这并不是太大的问题,但对于那些不了解实际情况的人,比如nicomp,它会创造一个严重错误的心理模型,导致程序不按照他们的预期行为运行,因为他们认为他们正在通过引用传递值,而实际上并不是这样。如果将引用按值传递和值按引用传递具有相同的语义,那么区分它们就不重要了,但它们的行为是不同的。 - Servy
显示剩余9条评论
4个回答

10

不,那不正确。

C#默认情况下使用按值传递参数的方式,这意味着你得到的是变量的一个副本。但是需要注意的是,被复制的只是变量本身,而不一定是对象;如果变量是引用类型(例如数组),那么变量实际上只是指向存储该对象的内存地址的“指针”。因此,当您将该变量传递给方法调用时,引用确实被复制了,但它仍然指向原始变量所指向的完全相同的对象。

当参数是值类型时,情况就非常不同了。在这种情况下,变量本身持有对象,因此您会得到您期望的行为。


但是,当我更改方法声明中参数(即数组)的值时,当我调用该方法时,该值不可见,而是显示更改之前的数组值。 - mdadil2019
@MohammadAdil 没错,因为你正在更改原始引用的副本。如果您想更改原始变量指向的内容,则需要通过引用传递参数。 - InBetween
1
那么,图书中的这些行想要解释什么,它是错误的吗? - mdadil2019
3
@MohammadAdil 不会。修改数组元素,例如 a[1] = 1;,会持久存在,因为参数指向与原始变量相同的对象。但是,执行以下操作 a = new[] { ...}不会持久存在,因为您正在将新引用分配给原始变量的副本。原始变量或其指向的数组不知道也不关心您刚刚将新数组分配给变量的副本。 - InBetween

8

这里有很多带有描述的答案。我来举个例子。假设这是你的方法:

public void ProcessData(int[] data)
{
  data[0] = 999;
}

如果你这样调用方法:
int[] dataToProcess = new int[] {1, 2, 3};
ProcessData(dataToProcess);
Console.WriteLine(dataToProcess[0]); //returns 999;

它将返回999,因为ProcessData访问数组的内存。

就像@InBetween所描述的那样:

在C#中,默认情况下通过副本传递参数,但复制的是变量

这意味着,如果您在方法中将数据设置为null:

public void ProcessData(int[] data)
{
  data = null;
}

它不会将您的dataToProcess设置为null。这意味着:

您正在向该方法传递指向数组内存的指针的副本。


1
数组是C#中的引用类型。这意味着每次将数组作为参数传递给任何函数时,都会传递该参数的引用(或指针)到该函数中。因此,在函数中对数组所做的任何修改也会在实际参数中进行。

如果我们在方法内修改作为参数传递的数组的内容,则对参数的副本进行修改,而不是原始参数,因此结果不可见。

这里所提到的行为是针对值类型而非引用类型的。C#中的值类型包括结构体和枚举,而引用类型则包括类和数组。

数组也发生了我在问题中解释的同样的事情。如果我更改方法声明,那么当我调用该方法时结果不会显示。 - mdadil2019
在C#中,默认情况下参数是按值传递的,如果要按引用传递参数,我们必须使用ref或out关键字。 - mdadil2019

1
在C#中,数组可以作为参数传递给方法。因为数组是引用类型,所以方法可以更改元素的值。如果需要进一步了解,请查看this msdn文档。

1
因为数组是引用类型,所以该方法可以更改元素的值。数组并不可变,只是因为它们是引用类型。它是可变的,也是引用类型。这里没有因果关系。 - Servy
我发现这个链接包含了有用的例子。谢谢。 - niki b

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接