【发布时间】:2018-08-27 17:45:37
【问题描述】:
我最近听说了 7.2 中的新 C# 功能,因此我们现在可以返回值类型的引用(例如 int),甚至可以返回值类型的只读引用。据我所知,值类型存储在堆栈中。当方法离开时,它们会从堆栈中删除。那么当 GetX 方法退出时 int 会发生什么?
private ref int GetX()
{
// myInt is living on the stack now right?
int myInt = 5;
return ref myInt;
}
private void CallGetX()
{
ref int returnedReference = ref GetX();
// where does the target of 'returnedReference' live now?
// Is it somehow moved to the heap, because the stack of 'GetX' was removed right?
}
我收到了错误
错误 CS8168:无法通过引用返回本地“myInt”,因为它不是本地引用 (11, 24)
那么为什么它不起作用?难道仅仅因为变量不能移动到堆中就不起作用吗?这是问题吗?如果它们不在堆栈中,我们是否只能通过引用返回值类型?我知道这是两个问题。
首先:ref 返回的值类型变量在哪里?堆栈还是堆? (我猜在堆上,但为什么)?
第二:为什么栈上创建的值类型不能通过引用返回?
所以这是可以编译的:
private int _myInt;
private ref int GetX()
{
// myInt is living on the stack now right?
_myInt = 5;
return ref _myInt;
}
private void CallGetX()
{
ref int returnedReference = ref GetX();
// where does the target of 'returnedReference' live now?
// Is it somehow moved to the heap? becase the stack of 'GetX' was removed right?
}
如果我理解你的 cmets 是因为现在 _myInt 不在方法 GetX 中,因此没有在堆栈中创建,对吗?
【问题讨论】:
-
堆与栈只是实现细节,与问题无关
-
“据我所知,值类型存储在堆栈中。” - 错误。
-
来自microsoft docs:返回值的生命周期必须超出方法的执行范围。换句话说,它不能是返回它的方法中的局部变量。它可以是类的实例或静态字段,也可以是传递给方法的参数。尝试返回局部变量会生成编译器错误 CS8168,“无法通过引用返回本地 'obj',因为它不是本地引用。”
-
新的
ref语法允许运行时使用指针。指针可以生成更高效的代码,它们可以避免复制值,但它们很危险。使用指向不再有效的内存位置的指针是一个非常传统的错误。 C# 编译器检查这些错误,它可以告诉方法返回后局部变量不再存在。因此将其标记为错误代码。 en.wikipedia.org/wiki/Dangling_pointer -
堆栈是一个实现细节,作者 Eric Lippert,blogs.msdn.microsoft.com/ericlippert/2009/04/27/…
标签: c# pass-by-reference heap-memory stack-memory c#-7.2