C#对象传递是按引用传递还是按值传递?

4
以下代码的输出让我感到惊讶。我认为“a”应该持有对新创建对象的引用。能否有人解释一下为什么结果不是2?
class Program
{
    static void Main(string[] args)
    {
        aclass a = new aclass();
        Process(a);
        Console.WriteLine(a.number);

        Console.ReadLine();
    }

    static void Process(aclass a)
    {
        aclass temp = new aclass();
        temp.number++;
        //Console.WriteLine(temp.number);

        a = temp;
        a.number++;
        //Console.WriteLine(a.number);
    }

}

class aclass
{
    public int number = 0;
}

编辑:这是一个面试问题。我刚意识到我长时间以来对概念的误解。虽然它们引用相同的地址,但参数a与原始a不同。


2
因为当你执行 a = temp 时,你会导致传递的参数与从那一点开始修改的内容之间的断开。如果你不这样做,你将在 Main 中得到 1 - Jon
在C#中,参数是按值传递而不是按引用传递的,请查看ref关键字。 - Alessandro D'Andria
1
你在两次递增tempnumber,但是你没有在Main中定义的a上做任何工作。 - Sam
@AlessandroD'Andria 我不确定你在这里的评论是否正确。 - mortdale
@mortdale 你是什么意思? - Alessandro D'Andria
3个回答

10

您并没有改变实际的原始引用,而只是改变了参数中保存的引用,这在微妙上并不相同,更改不会持久返回给调用者。您可以通过使用outref来更改此行为。

在这种情况下,您需要使用ref,因为您还传递了一个引用。

尝试:

class Program
{
    static void Main(string[] args)
    {
        aclass a = new aclass();
        Process(ref a);
        Console.WriteLine(a.number);

        Console.ReadLine();
    }

    static void Process(ref aclass a)
    {
        aclass temp = new aclass();
        temp.number++;
        //Console.WriteLine(temp.number);

        a = temp;
        a.number++;
        //Console.WriteLine(a.number);
    }

}

记住,使用 a = temp 会创建一个全新的引用。如果你只是想更新最初传入的现有类,则可以这样做:
a.number = temp.number;
a.number++;

这将取消使用ref的必要性。
您可以在MSDN上阅读更多内容: 传递引用类型参数 ref关键字 out关键字

这澄清了我对参数和原始对象的误解。虽然它们最初引用相同的值,但参数a是一个不同的对象,而不是原始的a。 - mortdale

0

这行代码 aclass a = new aclass(); 在内存中创建了一个变量(可以存储数据的空间)。假设它在内存中的地址是 *(0x12DF),并且存储在该位置的 value 是对象 a

这行代码 Process(a) 将对象 a 而不是地址传递给函数 Process,因此在 Process() 中发生的任何事情都与位置 *(0x12DF)contents 无关,因此在调用 Process() 前后,位置 *(0x12DF) 的内容将保持不变。

*(0x12DF)contents = a

希望这有所帮助,而不是增加更多的困惑!


我认为_Process(a)_传递的是内容的地址。_Process(aclass a)_中的参数是指向相同内容0x12DF的新对象。0x12DF中的内容从未被复制过。传递地址比传递整个值更有效率。如果_aclass_是值类型,那么参数_a_将是一个新对象,其值在不同的地址上被复制。 - mortdale

0

这基本上是传递引用类型的值和传递引用类型的引用之间的区别,如下:

  • 通过值传递引用类型 // Process(a);
  • 通过引用传递引用类型 // Process(ref a);

在示例中,Process(a) - 'a' 是一个引用类型,没有使用ref参数将其传递给方法。在这种情况下,传递到方法的是指向a的引用的副本。

在Process方法中使用new运算符分配新的内存空间,使变量'a'引用aclass的新对象。因此,在此之后进行的任何更改都不会影响原始对象'a'。

请参阅MSDN:http://msdn.microsoft.com/en-us/library/s6938f28.aspx


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