Подтвердить что ты не робот

Выполняется ли foreach() по ссылке?

Учтите это:

List<MyClass> obj_list = get_the_list();
foreach( MyClass obj in obj_list )
{
    obj.property = 42;
}

Является ли obj ссылкой на соответствующий объект в списке, чтобы при изменении свойства это изменение сохранялось в экземпляре объекта, когда-то построенном?

4b9b3361

Ответ 1

Да, obj - ссылка на текущий объект в коллекции (при условии, что MyClass - фактически класс). Если вы измените какие-либо свойства с помощью ссылки, вы меняете объект, как и ожидали.

Помните, однако, что вы не можете изменить переменную obj, так как она является переменной итерации. Если вы попробуете, вы получите ошибку компиляции. Это означает, что вы не можете его обнулить, и если вы повторяете типы значений, вы не можете изменять какие-либо элементы, поскольку это изменит значение.

Спецификация языка С# заявляет (8.8.4)

"Итерационная переменная соответствует локальная переменная, доступная только для чтения, с объем, который распространяется на встроенный утверждение".

Ответ 2

Да, пока вы не измените общий тип из списка в IEnumerable..

Ответ 3

Вы задали здесь 2 разных вопроса, давайте их в порядок.

Проводится ли цикл foreach по ссылке?

Если вы имеете в виду в том же смысле, что и цикл С++ для ссылки, то нет. С# не имеет ссылок на локальные переменные в том же смысле, что и С++, и, следовательно, не поддерживает этот тип итераций.

Будет ли сохраняться изменение

Предполагая, что MyClass является ссылочным типом, ответ да. Класс является ссылочным типом в .Net, и поэтому переменная итерации является ссылкой на одну переменную, а не на копию. Это не относится к типу значения.

Ответ 4

Хорошо, мне случилось, что мои изменения не обновлялись в цикле foreach, когда я повторялся через коллекцию var:

var players = this.GetAllPlayers();
foreach (Player player in players)
{
    player.Position = 1;
}

Когда я изменил var на List, он начал работать.

Ответ 5

В этом случае вы можете использовать (используя List<T>), но если вы будете выполнять итерацию по общему IEnumerable<T>, тогда он будет зависеть от его реализации.

Если бы это было все равно List<T> или T[], то все работало бы так, как ожидалось. Большая магия возникает, когда вы работаете с IEnumerable<T>, который был создан с использованием yield. В этом случае вы не можете больше изменять свойства T в рамках итерации и ожидать, что они будут присутствовать, если вы снова повторите те же самые IEnumerable<T>.

Ответ 6

это верно, если это не структура.

Ответ 7

Может быть, вам интересно полагать, что в версии С# 7.3 можно изменять значения по ссылке при условии, что свойство Current перечислителя возвращает ссылочный тип. Следующее будет действительным (дословная копия из документов MS):

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}

Подробнее об этой новой функции читайте на С# оператор foreach | Документы Microsoft.

Ответ 8

Ну, не понимая, что вы подразумеваете под "Итерацией по ссылке", я не могу ответить конкретно "да" или "нет", но могу сказать, что то, что происходит под поверхностью, состоит в том, что инфраструктура .net строит "счетчик" "класс для каждого клиентского кода вызывает вызов foreach в течение жизни foreach, который поддерживает ссылочный указатель на итерацию цикла, и каждый раз, когда ваш foreach выполняет итерацию, ir" поставляет "один элемент и" увеличивает "указатель или ссылку в перечислителе на следующий элемент...

Это происходит независимо от того, являются ли элементы в коллекции, которую вы итерируете, типами значений или ссылочными типами.

Ответ 9

obj - ссылка на элемент внутри Списка, поэтому, если вы измените его значение, оно будет сохраняться. Теперь, о чем вам следует беспокоиться, является ли get_the_list(); делает глубокую копию списка или возвращает тот же экземпляр.

Ответ 10

Да, это также почему вы не можете изменить перечислимый объект в контексте инструкции foreach.