Обновление структуры в цикле foreach в C # - PullRequest
7 голосов
/ 23 октября 2009

У меня есть этот код (C #):

using System.Collections.Generic;

namespace ConsoleApplication1
{
    public struct Thing
    {
        public string Name;
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Thing> things = new List<Thing>();
            foreach (Thing t in things) //  for each file
            {
                t.Name = "xxx";
            }
        }
    }
}

Не скомпилируется.
Ошибка:

Cannot modify members of 't' because it is a 'foreach iteration variable'

Если я изменю Thing на class, а не struct, он скомпилируется.

Пожалуйста, кто-нибудь может объяснить, что происходит?

Ответы [ 4 ]

9 голосов
/ 23 октября 2009

Более или менее то, что он говорит, компилятор не позволит вам изменить (части) циклического var в foreach.

Просто используйте:

for(int i = 0; i < things.Count; i+= 1) //  for each file
{
    things[i].Name = "xxx";
}

И это работает, когда Thing является классом, потому что тогда ваш цикл var является ссылкой, и вы вносите изменения только в объект, на который ссылаются, а не в саму ссылку.

7 голосов
/ 23 октября 2009

Структура - это не ссылочный тип, а тип значения.

Если у вас будет class вместо struct для Thing, цикл foreach создаст для вас ссылочную переменную, которая будет указывать на правильный элемент в вашем списке. Но поскольку это тип значения, он работает только с вашей копией Thing, которая в данном случае является итерационной переменной.

2 голосов
/ 23 октября 2009

Структура - это тип значения, а класс - это ссылочный тип.Вот почему он компилируется, когда это класс, но не когда это структура

Подробнее: http://www.albahari.com/valuevsreftypes.aspx

1 голос
/ 29 ноября 2017

Альтернативный синтаксис, который я предпочитаю решению @ Henk, таков:

DateTime[] dates = new DateTime[10];

foreach(int index in Enumerable.Range(0, dates.Length))
{
   ref DateTime date = ref dates[index];

   // Do stuff with date.
   // ...
}

Если вы выполняете разумный объем работы в цикле, то нет необходимости повторять индексирование везде, на первый взгляд.

P.S. DateTime на самом деле очень плохой пример, так как у него нет свойств, которые вы можете установить, но вы получите картину.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...