Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I return a reference to a local variable's field

Tags:

c#

c#-7.0

The documentation on ref returns and ref locals states:

The return value must have a lifetime that extends beyond the execution of the method. In other words, it cannot be a local variable in the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local."

I thought I understood this. I figured if I returned a reference to a local variable, then that variable might be collected and so my reference no longer references a variable.

However, I learned today that I can create a local variable then return a reference to a field on that local variable. To illustrate:

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;
      }
   }
}

How is this different from just returning a local? The local variable bar might be collected after GetInt returns, right? So what is barInt referencing if that happens?

I've tried C# versions 7.0, 7.1, 7.2, and 7.3 and it works on all of them.

like image 773
Joshua Robinson Avatar asked Oct 17 '25 10:10

Joshua Robinson


1 Answers

Consider this code example:

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

Both of these variables are held on the stack. Yes, they really are, even the object. The variable a is a pointer to the object, not the object itself, and that pointer is indeed a local variable on the stack.

So if you return a reference to either of these, it'll be a reference to some variable that was on the stack. The stack of course is overwritten when the call returns, which is why you can't ref return a local.

On the other hand, consider this example:

class Bar
{
    public int SomeInteger;
}

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

In this case, c is held on the stack as well. But the object that it references is on the heap, as is its field, SomeInteger. So you can safely return a reference to SomeInteger since it exists on the heap and the heap is not overwritten when the method returns.

like image 85
John Wu Avatar answered Oct 20 '25 00:10

John Wu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!