【问题标题】:c# Reference-Type by ref - Address to an Address?c# Reference-Type by ref - 地址到地址?
【发布时间】:2017-11-22 03:45:18
【问题描述】:

如果我通过引用传递一个引用类型,试图了解究竟发生了什么。我是这样理解的:

所以我有一个类 Foo,它代表一个引用类型

class Foo{ //Foo-stuff here }

所以就在这里

Foo f = new Foo();

Foo f(在堆栈上创建)保存实际对象的地址/引用,该对象在调用new Foo()时在堆中创建;

所以f 实际上拥有类似0x2A53BC 的东西

如果我调用一个方法来做这个

void Test(Foo g) { g = null; }

我只是传递“地址变量/引用变量”f 的地址。所以g 实际上指向堆栈中的f,而不是指向堆中的实际对象。所以我可以通过f更改堆中Foo对象的属性,因为我有f的地址,我可以通过f访问Foo,但是设置g=null只会杀死f变量的地址在堆栈中,而不是对堆本身中对象的引用。

但是有了这个

void Test(ref Foo g) { g = null; }

我实际上是在使用堆中那个 Foo-Object 的真实地址,所以使用 0x2A53BC。这意味着,我可以通过设置 g=null 来更改它指向的位置或终止从堆栈到堆的指针

这是对的吗?非常感谢!

【问题讨论】:

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


    【解决方案1】:

    所以Fooclass 类型,特别是引用类型。你有:

    var f = new Foo();
    

    所以f 实际上是对实际对象的引用。正如您所说,我们可能会将引用视为一个整数,例如 0x2A53BC(为了具体说明,我们实际上无法访问整数或 reference 的真正含义;那里是没有这些引用的指针算术)。

    现在,当您按值传递时,与重载一样:

    void Test(Foo g) { g = null; }
    

    我们用Test(f); 调用,值0x2A53BC复制到一个新的存储位置(堆栈上的一个新位置),并且那个新的存储位置变为g。如果您使用g 改变现有实例,那么由于两个存储位置都保存相同的信息0x2A53BC,您将改变f 指向的实例。但是您选择分配给g。这导致g 的新存储位置现在持有引用0x000000(我们简单地假设零用作null 的表示)。它显然不会改变f 的存储位置,它仍然指向位于0x2A53BC 的原始实例。

    相比之下,与其他重载:

    void Test(ref Foo g) { g = null; }
    

    我们用Test(ref f); 调用它,我们通过引用传递。所以g 使用相同的存储位置,就像我们已经为f 使用的那样。值0x2A53BC 不会被复制。当您分配g = null; 时,即原始 0x2A53BC0x000000 覆盖(null 的神奇表示)。当方法返回时,是的,甚至在它返回之前,f 已将其值更改为指向新的“地点”0x000000

    总结一下:引用类型的“价值”就是引用。当按值传递时,引用“数字”的副本将被调用的方法制作并使用。引用传递时,不复制值,被调用者方法和调用者方法使用相同的存储位置。


    补充:来自 C# 规范的一些引用:

    5.1.4 数值参数

    未使用 refout 修饰符声明的参数是 值参数

    值参数产生 在调用函数成员(方法、实例构造函数、 访问器或操作员)或参数的匿名函数 属于,并用给出的参数的值初始化 调用。值参数通常在返回时不存在 函数成员或匿名函数。 [...]

    5.1.5 参考参数

    使用ref 修饰符声明的参数是引用参数

    一个 引用参数不会创建新的存储位置。相反,一个 参考参数表示与 在函数成员或匿名中作为参数给出的变量 函数调用。因此,参考参数的值为 始终与基础变量相同。 [...]

    【讨论】:

    【解决方案2】:

    我只是传递“地址变量/引用变量”f 的地址。所以g实际上指向堆栈中的f,而不是堆中的实际对象。

    实际上你有它倒退。当您不使用 ref 时,g 将具有 f 的值(在您的示例中为 0x2A53BC复制到一个名为 g 的新变量中. gf 完全相互独立,但它们都持有“价值”0x2A53BC。当您执行g = null; 时,变量f 仍将保持0x2A53BC,但g 现在将保持0x000000

    注意:我不确定下一部分,我可能会告诉你事实上不正确的信息,但我描述的是外部观察者的正确行为。
    当您使用ref 时,变量g 将指向f 值的地址(比如说0x154AFA),而f 仍然指向0x2A53BC。当您执行g = null; 时,g 的值不会更新,它仍然指向0x154AFA,但是f 现在将指向0x000000

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-05
      • 2015-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多