foreach () выполняют итерации ссылкой?

Рассмотрите это:

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

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

64
задан The Codesee 30 September 2019 в 09:00
поделиться

5 ответов

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

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

В спецификации языка C # указано (8.8.4)

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

63
ответ дан 24 November 2019 в 15:48
поделиться

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

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

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

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

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

19
ответ дан 24 November 2019 в 15:48
поделиться

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

0
ответ дан 24 November 2019 в 15:48
поделиться

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

0
ответ дан 24 November 2019 в 15:48
поделиться

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

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

2
ответ дан 24 November 2019 в 15:48
поделиться