c# Reference-Type by ref - 地址到地址?
c# Reference-Type by ref - Address to an Address?
试图了解如果我通过其引用传递引用类型,究竟会发生什么。我是这样理解的:
所以我有一个Class Foo,代表一个Reference-Type
class Foo{ //Foo-stuff here }
所以就在这里
Foo f = new Foo();
Foo f
(在Stack上创建)持有实际Object的address/reference,调用new Foo()
时在Heap中创建;
所以 f
实际上持有类似 0x2A53BC
的东西
如果我调用方法执行此操作
void Test(Foo g) { g = null; }
我只是传递了"address-variable/reference-variable"f
的地址。所以 g
实际上指向堆栈中的 f
而不是堆中的实际对象。所以我可以通过 f
更改堆中 Foo 对象的属性,因为我有 f
的地址,我可以通过 f
访问 Foo,但是设置 g=null
只会杀死Stack 中 f
变量的地址,而不是 Heap 本身中对象的引用。
但是有了这个
void Test(ref Foo g) { g = null; }
我实际上是在处理堆中那个 Foo 对象的真实地址,所以是 0x2A53BC
。这意味着,我可以更改它指向的位置或通过设置 g=null
杀死从 Stack 到 Heap 的指针
这样对吗?非常感谢!
I just pass the address of the "address-variable/reference-variable" f
. So g
actually points to f
in the Stack but NOT to the actual Object in the Heap.
实际上你把它弄反了。当您不使用 ref
时,g 将具有 f
的值(在您的示例中 0x2A53BC
) copied 到一个名为 g
的新变量中。 g
和f
是完全独立的,但是他们都持有"value"0x2A53BC
。当您执行 g = null;
时,变量 f
仍将保持 0x2A53BC
但 g 现在将保持 0x000000
.
注意:我不确定下一部分,我可能会告诉你事实上不正确的信息,但我描述的是外部观察者的正确行为。
当您使用 ref
时,变量 g
将指向 f
值的地址(比方说 0x154AFA
)并且 f
仍然指向 0x2A53BC
。当您执行 g = null;
时,g
的值不会更新,它仍然指向 0x154AFA
,但是 f
现在将指向 0x000000
所以 Foo
是一个 class
类型,特别是引用类型。你有:
var f = new Foo();
所以 f
的 value 实际上是对实际对象的 reference。正如您所说,我们可能会将引用视为整数,比如 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);
调用,我们 通过引用传递 。因此 与 f
相同的存储位置 用于 g
。值 0x2A53BC
未被复制。当您分配 g = null;
时,即 原始 0x2A53BC
被 0x000000
覆盖(null
的神奇表示)。当方法 returns 时,是的,甚至在它 returns 之前,f
已将其值更改为指向新的 "place" 0x000000
.
总结一下:引用类型的"value"就是引用。当按值传递时,引用 "number" 的副本被创建并由调用的方法使用。当通过引用传递时,值不被复制,被调用方方法和调用方方法使用相同的存储位置。
补充:C# 规范中的一些引用:
5.1.4 Value parameters
A parameter declared without a ref
or out
modifier is a
value parameter.
A value parameter comes into existence
upon invocation of the function member (method, instance constructor,
accessor, or operator) or anonymous function to which the parameter
belongs, and is initialized with the value of the argument given in
the invocation. A value parameter normally ceases to exist upon return
of the function member or anonymous function. [...]
5.1.5 Reference parameters
A parameter declared with a ref
modifier is a reference parameter.
A
reference parameter does not create a new storage location. Instead, a
reference parameter represents the same storage location as the
variable given as the argument in the function member or anonymous
function invocation. Thus, the value of a reference parameter is
always the same as the underlying variable. [...]
试图了解如果我通过其引用传递引用类型,究竟会发生什么。我是这样理解的:
所以我有一个Class Foo,代表一个Reference-Type
class Foo{ //Foo-stuff here }
所以就在这里
Foo f = new Foo();
Foo f
(在Stack上创建)持有实际Object的address/reference,调用new Foo()
时在Heap中创建;
所以 f
实际上持有类似 0x2A53BC
如果我调用方法执行此操作
void Test(Foo g) { g = null; }
我只是传递了"address-variable/reference-variable"f
的地址。所以 g
实际上指向堆栈中的 f
而不是堆中的实际对象。所以我可以通过 f
更改堆中 Foo 对象的属性,因为我有 f
的地址,我可以通过 f
访问 Foo,但是设置 g=null
只会杀死Stack 中 f
变量的地址,而不是 Heap 本身中对象的引用。
但是有了这个
void Test(ref Foo g) { g = null; }
我实际上是在处理堆中那个 Foo 对象的真实地址,所以是 0x2A53BC
。这意味着,我可以更改它指向的位置或通过设置 g=null
这样对吗?非常感谢!
I just pass the address of the "address-variable/reference-variable"
f
. Sog
actually points tof
in the Stack but NOT to the actual Object in the Heap.
实际上你把它弄反了。当您不使用 ref
时,g 将具有 f
的值(在您的示例中 0x2A53BC
) copied 到一个名为 g
的新变量中。 g
和f
是完全独立的,但是他们都持有"value"0x2A53BC
。当您执行 g = null;
时,变量 f
仍将保持 0x2A53BC
但 g 现在将保持 0x000000
.
注意:我不确定下一部分,我可能会告诉你事实上不正确的信息,但我描述的是外部观察者的正确行为。
当您使用 ref
时,变量 g
将指向 f
值的地址(比方说 0x154AFA
)并且 f
仍然指向 0x2A53BC
。当您执行 g = null;
时,g
的值不会更新,它仍然指向 0x154AFA
,但是 f
现在将指向 0x000000
所以 Foo
是一个 class
类型,特别是引用类型。你有:
var f = new Foo();
所以 f
的 value 实际上是对实际对象的 reference。正如您所说,我们可能会将引用视为整数,比如 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);
调用,我们 通过引用传递 。因此 与 f
相同的存储位置 用于 g
。值 0x2A53BC
未被复制。当您分配 g = null;
时,即 原始 0x2A53BC
被 0x000000
覆盖(null
的神奇表示)。当方法 returns 时,是的,甚至在它 returns 之前,f
已将其值更改为指向新的 "place" 0x000000
.
总结一下:引用类型的"value"就是引用。当按值传递时,引用 "number" 的副本被创建并由调用的方法使用。当通过引用传递时,值不被复制,被调用方方法和调用方方法使用相同的存储位置。
补充:C# 规范中的一些引用:
5.1.4 Value parameters
A parameter declared without a
ref
orout
modifier is a value parameter.A value parameter comes into existence upon invocation of the function member (method, instance constructor, accessor, or operator) or anonymous function to which the parameter belongs, and is initialized with the value of the argument given in the invocation. A value parameter normally ceases to exist upon return of the function member or anonymous function. [...]
5.1.5 Reference parameters
A parameter declared with a
ref
modifier is a reference parameter.A reference parameter does not create a new storage location. Instead, a reference parameter represents the same storage location as the variable given as the argument in the function member or anonymous function invocation. Thus, the value of a reference parameter is always the same as the underlying variable. [...]