Почему возврат по ref не работает для элементов коллекций?

следующий пример возврата по ссылке из Что нового в 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 выражение не может использоваться в этом контексте, так как оно не может быть возвращено ссылка

почему возврат из массива работает, а возврат из коллекции-нет?

2 ответов


ответ находится в той же ссылке, которую вы опубликовали:

вы можете возвращать только ссылки, которые "безопасны для возврата": те, которые были перешел к вам, и те, которые указывают на поля, объектов.

ваш пример не удовлетворяет. Вы создаете список внутри функции (поэтому объект выйдет из области видимости и его указатель будет недействительным), а не указывать на поле объекта.


В C#ref работает:

  • переменные (локальные или параметров)
  • поля
  • ячейки массива

ref не работает:

  • свойства
  • событий
  • локальные переменные в случае возврата C# 7 по ref

обратите внимание, что для полей и местоположений массива не имеет значения, как вы получаете доступ к массиву. То есть, return ref numbers[i]; не держит на numbers, но в массив, на который он указывает. Совсем непохоже return ref numbers;, который может работать только если numbers был в поле.

тем не менее, вы используете ref на Dictionary<,>свойство индекса, это просто не поддерживаемое выражение для ref для начала (т. е. вы не можете пройти ref passwords[searchTerm] в качестве аргумента даже до C# 7), гораздо меньше, чтобы вернуться по ref.