Метод расширения с ref не работает с массивами - PullRequest
1 голос
/ 07 июня 2019

Я написал этот код:

public static T[][] Populate<T>(this ref T[][] arg, T with) where T : struct
{
    for (int i = 0; i < arg.Length; i++)
    {
        for (int j = 0; j < arg[i].Length; j++)
        {
            arg[i][j] = with;
        }
    }
    return arg;
}

И я получаю следующую ошибку:

error Почему это не работает? Аналогичная ситуация будет работать, когда this забирают, нет? И ограничения, кажется, соблюдены: я указал T должно быть struct; Я понимаю, что arg действительно массив, но какая разница? Неужели массив по умолчанию передается по ссылке, поэтому он недействителен?

Существуют ли какие-либо эквивалентные утверждения, которые я мог бы написать, которые не приводят к ошибкам?

Фу, прости за все вопросы. Спасибо.

Ответы [ 2 ]

4 голосов
/ 07 июня 2019

ref должно быть указано как в объявлении метода, так и при его вызове.

Если аргумент this расширения может быть передан по ссылке, не будет никакого способа указатьэто при вызове метода.

someObject.CallSomeExtensionMethod();

Куда бы мы положили ref?Нигде нет.

Если бы мы могли передать значение по ссылке, не зная , что мы передаем его по ссылке, могут произойти странные вещи.Обычно вызывается метод расширения, который изменяет значение, переданное в качестве первого аргумента.Например, мы могли бы написать метод расширения, чтобы перетасовать список:

list.Shuffle();

Мы ожидаем, что список будет изменен.Но представьте наше удивление, если метод расширения фактически заставил list указать на совершенно другой экземпляр List.Даже если бы мы знали, что это происходит, это было бы странно, но если бы такое поведение не было явным, это был бы хаос.Мы могли бы назвать расширение, которое не является ref, и кто-то мог бы изменить его на ref, не нарушая ничего, представляя всевозможные сумасшедшие, непредсказуемые эффекты.

Наличие ref как в методе, так и в методе.где он используется как контракт - этот метод говорит нам, что он может заменить нашу ссылку, и мы даем ему явное разрешение.

1 голос
/ 07 июня 2019

Это потому, что массивы являются ссылочными типами.
Итак, у вас есть ссылка на массив, содержащий другие ссылки на массивы, содержащие структуры.Тот факт, что содержимое массива является структурой, не означает, что сам массив является таковым.

Вам не нужно использовать ref при передаче массивов (, если вы изменяете только содержимое, а не ссылку ), потому что, как уже говорилось, они являются ссылочными типами,Это означает, что эта функция должна работать точно так, как вы хотите, если вы просто удалите ключевое слово ref.

Теперь я считаю, что это должно помочь вам, как исправить вашу ошибку.Однако я не указал, почему вы не можете использовать ref для extension-методов, и тем временем действительно хорошее объяснение уже опубликовано, так что иди проверь это тоже :)

Изменить:
Просто то, что я хотел добавить.Вам на самом деле не нужно возвращать массив снова, потому что все, что вы делаете - это изменяете вещи внутри (в конце концов, это всего лишь ссылка, поэтому эти изменения проходят без необходимости возвращать массив снова).

Вы хотели бы вернуть его, если либо:

a.Измените ссылку в текущей области и не используйте ключевое слово ref
b.Вы хотите объединить вызовы вместе, даже если вы используете ссылочный тип для создания небольшого количества синтаксического сахара (синтаксис типа app.UseX().UseY().UseZ()).

...