10

I have this code (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";
            }
        }
    }
}

It won't compile.
The error is:

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

If I change Thing to a class rather than a struct, however, it does compile.

Please can someone explain what's going on?

AJ.
  • 13,461
  • 19
  • 51
  • 63

4 Answers4

12

More or less what it says, the compiler won't let you change (parts of) the looping var in a foreach.

Simply use:

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

And it works when Thing is a class because then your looping var is a reference, and you only make changes to the referenced object, not to the reference itself.

H H
  • 263,252
  • 30
  • 330
  • 514
8

A struct is no reference type but a value type.

If you would have a class instead of a struct for Thing, the foreach loop would create a reference variable for you, that would point to the correct element in you list. But since it is a value type, it only operates on a copy of your Thing, which is in this case the iteration variable.

Johannes Rudolph
  • 35,298
  • 14
  • 114
  • 172
  • Yes, it is relevant. Because it is a value type, the entire struct is the looping variable and therefore no part of it can be modified. – Robin Day Oct 23 '09 at 10:36
  • Thanks for explaining the differene, Johannes. Much appreciated. +1 – AJ. Oct 23 '09 at 10:41
4

An alternate syntax that I prefer to @Henk's solution is this.

DateTime[] dates = new DateTime[10];

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

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

If you are doing a reasonable amount of work in the loop then not having to repeat the indexing everywhere is easier on the eye imo.

P.S. DateTime is actually a really poor example as it doesn't have any properties you can set, but you get the picture.

Neutrino
  • 8,496
  • 4
  • 57
  • 83
3

A struct is a value type but a class is a reference type. That's why it compiles when This is a class but not when it is a struct

See more: http://www.albahari.com/valuevsreftypes.aspx

armannvg
  • 1,736
  • 1
  • 15
  • 29