为什么我可以ref返回仅存在于方法内的数组项?

Cod*_*r14 8 ref c#-7.0

我正在尝试C#7的新ref参考.

我能够编译和构建这个:

        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!
    }
Run Code Online (Sandbox Code Playgroud)

根据MSDN:返回值不能是返回它的方法中的局部变量; 它的范围必须超出返回它的方法.它可以是类的实例或静态字段,也可以是传递给方法的参数.尝试返回局部变量会生成编译器错误CS8168,"无法通过引用返回本地'obj',因为它不是ref本地."

那为什么这会编译?当我执行此方法时,返回的引用显示正确的字符串.

Jon*_*eet 13

可以将数组元素看作是数组的实例字段.想象一下你的阵列是:

public class FourElementStringArray
{
    public string element0;
    public string element1;
    public string element2;
    public string element3;
}
Run Code Online (Sandbox Code Playgroud)

那么你的代码相当于:

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;
}
Run Code Online (Sandbox Code Playgroud)

这符合您引用的文档:

它可以是类的实例或静态字段,也可以是传递给方法的参数.

这有用吗?不是特别.危险吗?没有.

后一部分是重点.使用常规数组,如果调用者分配了一个新值,那很好 - 它正在替换堆上的数组元素.当数组元素引用存在时,不能对数组进行垃圾回收; 一切都基本没问题.

编译器规则试图阻止的是使用返回的引用到堆栈上的某个地方,然后由返回的方法弹出.数组本身不在堆栈中,因此这里没有问题.

  • @ Coder14:字符串本身是,但*变量*不是.局部变量本身的类型无关紧要 - 重要的是你不能通过引用返回局部变量,因为在方法返回时,该变量将不再存在.当您通过引用返回引用类型对象中的数组元素或字段时,情况并非如此. (2认同)

And*_*y G 5

请参阅此处的说明:

无法返回本地int变量而不是数组.int是一个值类型,因此变量超出了方法末尾的范围,因此无法返回对它的引用.这与数组有所不同.数组是引用类型,数组在堆上分配.可以使用ref关键字返回数组中的int.

您无法直接返回整数值,因为它是值类型.可以返回数组元素,因为它是引用类型.MSDN语句是正确的.

...仅存在于方法内的数组

返回的引用将数组保留在方法调用之外.