【问题标题】:Why doesn't returning by ref work for elements of collections?为什么按 ref 返回对集合元素不起作用?
【发布时间】:2017-09-20 10:46:50
【问题描述】:

下面引用返回的例子来自What’s New in C# 7.0

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number)
        {
            return ref numbers[i]; // return the storage location, not the value
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} not found");
}

编译没有任何问题(正如您所期望的,因为它是从 Microsoft 博客复制的)。

我写了这个:

private static ref int GetReference(string searchTerm)
{
    var passwords = new Dictionary<string, int>
    {
        {"password", 1},
        {"123456", 2},
        {"12345678", 3},
        {"1234", 4},
        {"qwerty", 5},
        {"12345", 6},
        {"dragon", 7}
    };

    return ref passwords[searchTerm];
}

这个不能编译;它给出了以下错误:

CS8156 无法在此上下文中使用表达式,因为它可能不会通过引用返回

为什么从数组返回有效,而从集合返回无效?

【问题讨论】:

  • 由于您在方法内声明了password,因此当从GetReference 返回时,它超出了范围。 GC 将(最终)删除对其的所有引用,您将无法访问正确的数据。
  • 如果passwords 通过参数列表传递给方法,它会起作用,就像你的第一个例子一样。
  • 我的第一次尝试是将它作为一个字段,但这也不起作用。看来它必须实际传入,而不仅仅是在范围内。
  • 数组与字典不同。即使是 C# 6 中的 pre-ref 返回,您也可以将数组槽作为 ref 传递给方法,但索引器(如字典或列表中)不能。

标签: c# .net c#-7.0


【解决方案1】:

在 C# 中,ref 适用于:

  • 变量(本地或参数)
  • 字段
  • 阵列位置

ref 不适用于:

  • 属性
  • 活动
  • C# 7 中的局部变量由 ref 返回

请注意,对于字段和数组位置,您如何访问数组并不重要。也就是说,return ref numbers[i]; 不保留 numbers,而是保留它指向的数组。与return ref numbers; 完全不同,后者只有在numbers 是一个字段时才有效。

但是,您在Dictionary&lt;,&gt; 的索引属性上使用ref,它根本不支持ref 开头的表达式(即,您甚至不能在之前将ref passwords[searchTerm] 作为参数传递C# 7),更不用说通过 ref 来返回了。

【讨论】:

    【解决方案2】:

    答案在您发布的同一个链接中:

    您只能返回“安全返回”的 ref: 传递给您,以及指向对象中的字段的那些。

    你的例子都不满足。您正在函数内部创建列表(因此对象将超出范围并且其指针将无效),并且它不指向对象的字段。

    【讨论】:

    • 不仅仅是字段。它也是可以作为 refs 传递的数组槽。
    • 还有更多:Dictionary&lt;,&gt; 的索引属性不是ref 的有效表达式。您不能提供 ref passwords[searchTerm] 作为 ref 参数。因此,编译器不会评估 ref 是否可以安全返回,因为它根本不是有效的 ref。
    • @acelent 是的,我同意。这个答案具有误导性。这与passwords 是本地人无关。这是因为 ref 表达式正在调用索引器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-22
    • 2014-06-14
    • 1970-01-01
    • 2010-09-09
    • 2013-08-11
    • 2020-04-13
    相关资源
    最近更新 更多