Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#引用类型按引用-地址到地址?_C#_Pointers_Reference_Pass By Reference - Fatal编程技术网

c#引用类型按引用-地址到地址?

c#引用类型按引用-地址到地址?,c#,pointers,reference,pass-by-reference,C#,Pointers,Reference,Pass By Reference,如果我通过引用传递引用类型,试图理解到底发生了什么。我是这样理解的: 所以我有一个类Foo,它表示一个引用类型 class Foo{ //Foo-stuff here } 就在这里 Foo f = new Foo(); Foo f(在堆栈上创建)保存实际对象的地址/引用,该对象在调用new Foo()时在堆中创建 所以f实际上包含类似0x2A53BC 如果我调用这样做的方法 void Test(Foo g) { g = null; } 我只需传递“地址变量/参考变量”的地址f。因此g实际上

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

所以我有一个类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
变量的地址,而不是堆中对象本身的引用

但是有了这个

无效测试(ref Foo g){g=null;}

我实际上是在使用堆中那个Foo对象的真实地址,所以使用
0x2A53BC
。这意味着,我可以通过设置
g=null

是这样吗?多谢各位

我只需传递“地址变量/参考变量”的地址
f
。因此
g
实际上指向堆栈中的
f
,而不是堆中的实际对象

事实上你把它倒过来了。不使用
ref
g时,g的值将为
f
(在您的示例中为
0x2A53BC
复制到名为
g
的新变量中
g
f
彼此完全独立,但它们都持有“值”
0x2A53BC
。当您执行
g=null时
变量
f
仍将保持
0x2A53BC
,但g现在将保持
0x000000

注意:我不确定下一部分的内容,我可能会告诉您事实上不正确的信息,但我是在描述外部观察者的正确行为。

使用
ref
时,变量
g
将指向
f
值的地址(比如
0x154AFA
),而
f
仍然指向
0x2A53BC
。当您执行
g=null时
g的值不会更新,它仍然指向
0x154AFA
,但是
f
现在将指向
0x000000
,因此
Foo
类型,尤其是引用类型。你有:

var f = new Foo();
因此
f
的值实际上是对实际对象的引用。正如您所说,我们可能认为引用是一个整数,比如说
0x2A53BC
(为了具体起见,我们实际上无法访问整数或任何引用;这些引用没有指针算法)

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

void Test(Foo g) { g = null; }
void Test(ref Foo g) { g = null; }
我们称之为
Test(f)
,值
0x2A53BC
复制到一个新的存储位置(堆栈上的新位置),该新存储位置将变为
g
。如果您使用了
g
来变异现有实例,那么由于两个存储位置都保存相同的信息
0x2A53BC
,因此您也会变异
f
指向的实例。但是您可以选择分配给
g
。这导致了
g
的新存储位置出现了一个错误,现在保存着引用
0x000000
(我们简单地假设零被用作
null
的表示)。它显然不会更改
f
的存储位置,它仍然指向位于
0x2A53BC
的原始实例

相反,对于其他过载:

void Test(Foo g) { g = null; }
void Test(ref Foo g) { g = null; }
我们称之为
Test(参考f),我们通过引用传递。因此,
g
使用的存储位置与对
f
使用的存储位置相同。未复制值
0x2A53BC
。当您分配
g=null时
,即原始的
0x2A53BC
0x000000
(null
的神奇表示法)覆盖。当方法返回时,即使在返回之前,
f
已将其值更改为指向新的“位置”
0x000000

总而言之:引用类型的“值”就是引用。按值传递时,将生成引用“number”的副本,并由调用的方法使用。通过引用传递时,不会复制值,被调用方方法和调用方方法使用相同的存储位置


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

5.1.4数值参数

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

一个值参数出现了 调用函数成员(方法、实例构造函数、, 访问器(或运算符)或匿名函数 属于,并使用中给定的参数值初始化 调用。返回时,值参数通常不再存在 函数成员或匿名函数的名称。[……]

5.1.5参考参数

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

A 引用参数不会创建新的存储位置。取而代之的是 reference参数表示的存储位置与 在函数成员或匿名中作为参数给定的变量 函数调用。因此,参考参数的值是 始终与基础变量相同。[……]

旧相关thr