为什么我要返回对局部变量字段的引用

时间:2019-09-06 21:59:16

标签: c# c#-7.0

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版本,并且适用于所有版本。

1 个答案:

答案 0 :(得分:6)

考虑以下代码示例:

void Foo()
{
    object a;
    int b;
}

这两个变量都保存在堆栈中。是的,它们确实是,甚至是物体。变量a是指向对象的指针,而不是对象本身,并且该指针确实是堆栈上的局部变量。

因此,如果您返回对这两个变量的引用,它将是对堆栈上某个变量的引用。当调用返回时,堆栈当然会被覆盖,这就是为什么您不能引用返回本地变量的原因。

另一方面,请考虑以下示例:

class Bar
{
    public int SomeInteger;
}

void Foo()
{
    Bar c = new Bar();
}

在这种情况下,c也保留在堆栈中。但是它引用的对象以及其字段SomeInteger都在堆上。因此,您可以安全地返回对SomeInteger的引用,因为它存在于堆中,并且在方法返回时不会覆盖堆。