值类型变量 - 由ref返回 - 在哪里生效?堆栈还是堆?

Dan*_*iel 5 c# heap stack pass-by-reference c#-7.2

我最近听说过7.2中的新C#Feature,所以我们现在可以返回值类型的引用(例如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?
}
Run Code Online (Sandbox Code Playgroud)

我收到了错误

错误CS8168:无法通过引用返回本地'myInt',因为它不是ref本地(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?
}
Run Code Online (Sandbox Code Playgroud)

如果我理解你的评论是正确的,那是因为现在_myInt不在方法内部GetX而且不会在堆栈中创建吗?

Evk*_*Evk 3

我觉得你已经明白为什么它不起作用了。您不能通过方法的引用返回局部变量(除非它是 ref local),因为在大多数情况下,局部变量的生命周期是方法,因此它在方法之外的引用没有任何意义(在方法之外,该变量是死的,位置在哪里)以前可能包含任何东西)。正如文档所述:

返回值的生命周期必须超出方法的执行时间。换句话说,它不能是返回它的方法中的局部变量

实际上,一些局部变量的生存时间可能比它们声明的方法的执行时间长。例如,由闭包捕获的变量:

int myLocal = 5;
SomeMethodWhichAcceptsDelegate(() => DoStuff(myLocal));
return ref myLocal;
Run Code Online (Sandbox Code Playgroud)

然而,这会带来额外的复杂性,而没有任何好处,因此这也是被禁止的,即使 的生命周期myLocal可能比包含方法长得多。

最好不要从栈和堆的角度来考虑。例如,您可能认为无法从方法 via 返回对堆栈上分配的内容的引用ref return。这不是真的,例如:

private void Test() {
    int myLocal = 4;
    GetX(ref myLocal);       
}

private ref int GetX(ref int i) {            
    return ref i;
}
Run Code Online (Sandbox Code Playgroud)

这里myLocal显然是在堆栈上,我们通过引用传递它GetX,然后用 . 返回这个(堆栈分配的)变量return ref

因此,只需从变量生命周期的角度来考虑它,而不是堆栈\堆。

在第二个示例中,_myInt字段的生命周期显然比 的执行长GetX,因此通过引用返回它没有问题。

另请注意,无论您返回值类型还是引用类型,return ref在这个问题的上下文中都没有任何区别。