Обновить структуру в цикле foreach в C#
Вопрос
У меня есть этот код (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
к a class
вместо того, чтобы struct
, однако, он компилируется.
Пожалуйста, кто-нибудь может объяснить, что происходит?
Решение
Более или менее то, что он говорит, компилятор не позволит вам изменить (части) циклического var в foreach. Р>
Просто используйте:
for(int i = 0; i < things.Count; i+= 1) // for each file
{
things[i].Name = "xxx";
}
И это работает, когда Thing
является классом, потому что тогда ваш зацикленный var является ссылкой, а вы вносите изменения только в объект, на который есть ссылка, а не в саму ссылку.
Другие советы
Структура - это не ссылочный тип, а тип значения.
Если бы у вас класс
для Thing
был class
, цикл foreach создал бы для вас ссылочную переменную, что бы укажите на правильный элемент в вашем списке. Но поскольку это тип значения, он работает только с копией вашего Thing
, который в данном случае является итерационной переменной.
Структура - это тип значения, а класс - это ссылочный тип. Вот почему он компилируется, когда это класс, но не когда это структура
Подробнее: http://www.albahari.com/valuevsreftypes.aspx р>
Альтернативный синтаксис, который я предпочитаю решению @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.
// ...
}
Если вы выполняете разумный объем работы в цикле, то отсутствие необходимости повторять индексацию везде проще на глаз, imo.
P.S.DateTime на самом деле является действительно плохим примером, поскольку у него нет никаких свойств, которые вы могли бы установить, но вы получаете картинку.