C#7.0中通过引用返回的值是否存储在堆栈或堆中?
由于引入了C#7.0的按引用返回特性,并且根据我的理解,像这样的特性需要在编译器上重新布线,以便仅在堆上的变量上存储此引用,那么是否可以在堆栈上存储对变量的返回引用,或者新的ref声明是否确保变量始终存储在堆上C#7.0中通过引用返回的值是否存储在堆栈或堆中?,c#,clr,C#,Clr,由于引入了C#7.0的按引用返回特性,并且根据我的理解,像这样的特性需要在编译器上重新布线,以便仅在堆上的变量上存储此引用,那么是否可以在堆栈上存储对变量的返回引用,或者新的ref声明是否确保变量始终存储在堆上 ref int x = ref DoSomething(data); // Is the value of x now on the stack or the heap? Or is x stored on the stack as a reference and the value
ref int x = ref DoSomething(data);
// Is the value of x now on the stack or the heap? Or is x stored on the stack as a reference and the value on the heap?
我的理解基于:
最后,CLR允许“ref返回类型”;理论上你可以
有一个方法“ref int M(){…}”,该方法返回对
整数变量。如果出于某种奇怪的原因我们决定允许
在C#中,我们必须修复编译器和验证器,以便
确保只能将引用返回到
已知在堆上,或已知在堆栈上“较低”
而不是被叫人
这首歌的名字叫“哈多克斯的眼睛”
“哦,这就是这首歌的名字,是吗?”爱丽丝说,试图表现出兴趣。
“不,你不明白,”骑士说,看起来有点恼火这就是它的名字。这个名字真的是“老人”
“那么我应该说“这就是这首歌的名字”?”爱丽丝纠正了自己。
“不,你不应该这样,那完全是另一回事了!这首歌叫做“方式和方法”:但你知道,那只是它的名字
“那么,这首歌是什么?”爱丽丝说,这时她完全不知所措了。
“我正打算这么做,”骑士说这首歌真的是“坐在门上”:这首曲子是我自己的发明
这首歌,这首歌的名字,名字叫什么,这首歌叫什么,显然都不一样
有三件事你不能混淆:
- 变量引用的位置--别名
- 引用变量的位置--别名变量
- 如果引用的变量为引用类型,则引用对象的位置(如有)
现在x的值是在堆栈上还是在堆上 表达式
x
是另一个变量的别名
该变量有一个值
假设别名变量是值类型。别名变量及其值是在临时池(也称为“堆栈”)还是在长期池(称为“堆”)上?我们不知道。我们也不在乎。我们知道,无论它是什么,我们都可以保证这个变量现在是活动的
然而,我们可以猜测:ref返回的变量通常是堆分配变量的别名,因为我们确定它们是活动的
假设别名变量为引用类型。引用存储在堆栈还是堆上?同样,出于同样的原因,我们也不知道。该引用的引用对象是在堆栈上还是在堆上?它要么在堆上,要么为null;我们对此有保证
或者x作为引用和堆上的值存储在堆栈上
ref int x = ref DoSomething(data);
// Is the value of x now on the stack or the heap? Or is x stored on the stack as a reference and the value on the heap?
通过
x
您是指x
别名的变量,还是指本地x
本身?本地数据本身存储在堆栈或寄存器中;不得将其吊至封闭类场地。别名的变量可能在任何地方,但如上所述,很可能在堆上。ref int x
是int*x
的语法糖,即变量在运行时的行为方式。当您将变量作为参数传递给方法并且参数声明为ref
时,调用者会传递指向该变量的指针,这与您得到的行为完全相同。指针不关心值存储在哪里,实际上可以存储在任何地方。请注意,您不能传递属性,它没有存储空间
他们在C#v7中必须做的一件非常重要的事情是确保您不会意外地创建一个。像C和C++这样的语言臭名昭著,它是那些没有编译器要求生成诊断的语言中的未定义行为。许多带有该缺陷的程序似乎运行得很好,直到程序中看似微不足道的更改(添加函数调用)破坏了指向的值
实际上并不难,被调用方法的局部变量是麻烦制造者。方法返回后,它们不再存在,因此引用无效。在C#v7中会出现编译错误的特定场景。但是如果局部变量是调用方之一,并且它通过参数传入引用,则可以,该变量仍处于活动状态。如果它是局部变量,则它将在堆栈上等待sure@EhsanSajjad如果它只是一个局部变量,那么你就不能从
ref
返回方法返回它。你能详细说明一下你说@Servy是什么意思吗?@EhsanSajjad自己试试看。它不会编译,编译器错误将或多或少地告诉您我告诉您的内容。如果您可以从ref返回方法返回对局部变量的引用,那么您将拥有对范围外变量的引用,而C#不允许这样做。您从Eric引用的内容回答了您的问题。返回的引用需要是对堆中某个值的引用,或者是对堆栈上更高的值的引用。也可以是,我喜欢你的答案。但C#7如何确保变量在创建别名时处于活动状态?我现在无法尝试,但在同一个方法中返回对局部变量(堆栈上)的引用是否有效?@illdans4:编译器必须跟踪每个引用的来源和发生的情况。将我们知道是本地的ref返回给本地的ref是不合法的。在所有情况下都可以这样做吗?如果在另一个已经编译的程序集中有一个ref-returning-ref-taking方法,该方法只返回提供给它的引用,该怎么办?即使在这种情况下,编译器也会检查方法吗?@illdans4:好问题。全部d