The documentation on ref returns and ref locals状态:
返回值的寿命必须超出方法的执行范围。换句话说,它不能是返回它的方法中的局部变量。它可以是类的实例或静态字段,也可以是传递给方法的参数。尝试返回本地变量会生成编译器错误CS8168,“由于不是参考本地,因此无法通过参考返回本地'obj'。”
我以为我明白了。我发现如果我返回了对局部变量的引用,那么可能会收集该变量,因此我的引用不再引用变量。
但是,我今天了解到,我可以创建一个局部变量,然后返回对该局部变量上的字段的引用。为了说明:
using System;
namespace IAmConfused
{
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
ref int barInt = ref foo.GetInt();
Console.WriteLine(barInt); //Outputs 123
barInt = 354;
Console.WriteLine(barInt); //Outputs 354
}
}
public class Foo
{
public ref int GetInt()
{
// int x = 123;
// return ref x; //CS8168
var bar = new Bar(123);
return ref bar.Value;
}
class Bar
{
public Bar(int v)
{
Value = v;
}
public int Value;
}
}
}
这与仅返回本地人有何不同? bar
返回后可能会收集局部变量GetInt
,对吗?那么,barInt
指的是什么呢?
我已经尝试过C#
的7.0、7.1、7.2和7.3版本,并且适用于所有版本。
答案 0 :(得分:6)
考虑以下代码示例:
void Foo()
{
object a;
int b;
}
这两个变量都保存在堆栈中。是的,它们确实是,甚至是物体。变量a
是指向对象的指针,而不是对象本身,并且该指针确实是堆栈上的局部变量。
因此,如果您返回对这两个变量的引用,它将是对堆栈上某个变量的引用。当调用返回时,堆栈当然会被覆盖,这就是为什么您不能引用返回本地变量的原因。
另一方面,请考虑以下示例:
class Bar
{
public int SomeInteger;
}
void Foo()
{
Bar c = new Bar();
}
在这种情况下,c
也保留在堆栈中。但是它引用的对象以及其字段SomeInteger
都在堆上。因此,您可以安全地返回对SomeInteger
的引用,因为它存在于堆中,并且在方法返回时不会覆盖堆。