Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I ref return an item of an array that only exists inside the method?

Tags:

ref

c#-7.0

I was trying out the new ref returns of C#7.

I am able to compile and build this:

        public ref string MisUseRefReturn(int index)
    {
        string[] array = { "a", "b", "c", "d" };
        return ref array[index]; //array[2] gets out of scope when this method returns!
    }

According to MSDN: The return value cannot be a local variable in the method that returns it; it must have a scope that is outside 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."

So why does this compile? When I execute this method, the returned reference shows the correct string.

like image 989
Coder14 Avatar asked Jan 03 '18 10:01

Coder14


2 Answers

Think of the array element as if it were an instance field of the array. Imagine your array were:

public class FourElementStringArray
{
    public string element0;
    public string element1;
    public string element2;
    public string element3;
}

Then your code is equivalent to:

public ref string MisUseRefReturn(int index)
{
    var array = new FourElementStringArray
    {
        element0 = "a",
        element1 = "b",
        element2 = "c",
        element3 = "d"
    };
    // TODO: do this dynamically based on index
    return ref array.element2;
}

That abides by the piece of documentation you quoted:

It can be an instance or static field of a class, or it can be an argument passed to the method.

Is this useful? Not particularly. Is it dangerous? No.

The latter part is the important point. Using the regular array, if the caller assigns a new value, that's fine - it's replacing an element of an array, on the heap. The array can't be garbage collected while the array element reference exists; all is basically okay.

What the compiler rule is trying to prevent is the use of a returned reference to somewhere on the stack which has then been popped by the method returning. The array itself isn't on the stack, so there's no problem here.

like image 196
Jon Skeet Avatar answered Oct 21 '22 12:10

Jon Skeet


See the description here:

Returning a local int variable instead of an array is not possible. int is a value type, and thus the variable gets out of scope at the end of the method, and thus a reference to it cannot be returned. That’s different with an array. An array is a reference type, and the array is allocated on the heap. An int within the array can be returned with the ref keyword.

You could not return an integer value directly as it is a value type. An array element can be returned because it is a reference type. The MSDN statement is correct.

... of an array that only exists inside the method

The returned reference persists the array beyond the method call.

like image 23
Andy G Avatar answered Oct 21 '22 11:10

Andy G