通过引用将引用类型作为参数传递

时间:2014-04-10 21:36:10

标签: c# oop parameters reference

好吧,我正试图围绕堆叠和堆积以及引用类型与值类型之间的差异而不是什么,现在我认为我对此有了一个非常基本的理解,但今天我遇到了一个令人难以置信的例子我想澄清一下:

public class Thing
{
}

public class Animal : Thing
{
    public int Weight;
}

public class Vegetable : Thing
{
    public int Length;
}

public void Go()
{
    Thing x = new Animal();
    Switcharoo(ref x);

    Console.WriteLine(
        "x is Animal    :   "
        + (x is Animal).ToString());
    Console.WriteLine(
        "x is Vegetable :   "
        + (x is Vegetable).ToString());
}

public void Switcharoo(ref Thing pValue)
{
    pValue = new Vegetable();
}

现在,在此示例中,x的类型将从Animal转到Vegetable。我必须承认,我不太明白为什么,当我们传递x时,我们不是将引用传递给Animal对象所在的堆上的内存地址?在这种情况下,对我来说,Switcharoo唯一能做的就是创建一个Vegetable的新实例,在该方法执行完成后将成为“孤立”的实例。

3 个答案:

答案 0 :(得分:2)

当您通过引用传递时,您实际上正在为变量创建别名,因此在Switcharoo中,pValuex方法中Go的别名。因此,分配给pValue是对x的分配。

xGo的类型为Thing,并且在运行时,它最初指向类Animal的实例。调用Switcharoo后,x将指向Vegetable类的实例。原始Animal实例现在无法访问,可以收集。

使用ref时,它是通过引用传递的变量,因此它对引用和值类型(如int)的工作方式相同。在Go中,x将(可能)存在于堆栈中,在调用Switcharoo之前,其值将是Animal实例的地址。在Switcharoo内,pValue是变量x的别名。这可以实现为Go中变量的指针,但ref的语义不需要使用指针。

规范描述了ref参数的语义:

5.1.5参考参数

  

参考参数不会创建新的存储位置。代替,   引用参数表示与之相同的存储位置   变量作为函数成员或匿名中的参数给出   函数调用。因此,参考参数的值总是如此   与基础变量相同。

答案 1 :(得分:2)

如果通过引用传递参数,则传递对原始值的引用,并且可以更改此原始值。如果此值是引用类型,那么方法获得的是对引用的引用!

这允许该方法更改原始引用。 Switcharoo的作用是将新的Vegetable分配给x


如果参数不是引用,则该方法获取原始值的副本。但是,如果参数类型是引用类型,则该方法仍然可以更改引用的原始对象的属性,但它不能更改原始引用,因为它只获取原始引用的副本。然后,该方法只能更改其引用的本地副本。


参考

   Thing x
  +-------+          +--------+
  |   O---|--------->| object |
  +-------+          +--------+
        ^
        |
public void Switcharoo(ref Thing pValue)
{       |
    +---|---+
    |   O   | pValue
    +-------+
}

按价值

   Thing x  
  +-------+          +--------+  
  |   O---|--------->| object |
  +-------+          +--------+
                         ^
                         |
public void Switcharoo(Thing pValue)
{    pValue              |
    +-------+            |
    |   O---|------------+ 
    +-------+
}

答案 2 :(得分:1)

使用ref传递引用类型时,意味着您可以更改引用本身。这意味着在您的情况下,您将创建一个新的Vegetable并将其引用放在x中。

现在没有refx内的Switcharoox内的Go不同,但ref会更改x。现在它们具有相同的价值。

从概念上讲,您正在做的是发送对Animal的引用,x本身就是对Vegetable的引用。当您进行更改时,{{1}}会保留对您的新{{1}}。

的引用

按值传递参考类型:

  1. x = new Animal() - > x = 0x0001。 (0x0001是动物的记忆位置)
  2. Switcharoo() - > x = 0x0001,pValue = 0x0001。
  3. pValue = new Vegetable() - > x = 0x0001和pValue = 0x0002(0x0002是蔬菜的内存位置)
  4. Switcharoo()结束 - > x = 0x0001
  5. 通过参考传递参考类型:

    1. x = new Animal() - > x = 0x0001。
    2. Switcharoo() - > x = 0x0001,pValue = 0x0001。
    3. pValue = new Vegetable() - > x = 0x0002和p​​Value = 0x0002(因为x和pValue是包含0x0002的相同内存位置的2个名称)
    4. Switcharoo()结束 - > x = 0x0002