#1,121 – Modifying Elements in a Collection Using foreach

Although the iteration variable in a foreach loop is read-only, you can still use the iteration variable to modify the elements of a collection, as long as they are reference-typed.  (Value-typed elements are immutable).  You’re not changing the iteration variable, but rather changing the object that it refers to.

            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2},
                    new Dog {Name = "Jack", Age = 17}
                };

            foreach (Dog d in myDogs)
            {
                Console.Write(string.Format("{0} / ", d));
                d.Age++;
                Console.WriteLine(d);
            }

1121-001

Advertisements

#1,120 – The Iteration Variable in a foreach Loop Is Read-Only

Unlike the for loop, the iteration variable in a foreach loop is read-only.  Attempting to assign a value to the variable within the body of the loop will result in a compile-time error.

            string[] dogs = {"Kirby", "Jack", "Ruby", "Lassie"};

            // for loop allows writing to iteration variable
            Console.WriteLine("= for loop");
            for (int i = 0; i < dogs.Length; i++)
            {
                Console.WriteLine(dogs[i]);
                if (dogs[i].StartsWith("J"))
                    i++;  // skip next
            }

            Console.WriteLine("= foreach loop");
            foreach (string s in dogs)
            {
                if (s.StartsWith("J"))
                    s = "****";     // ERROR
                Console.WriteLine(s);
            }

1120-001

#1,119 – Scope of Iteration Variable Is Limited to Body of foreach

The iteration variable that is set to a new element during each pass of a foreach statement only has scope within the body of the foreach loop.  It may not be used or referenced outside of the loop.

            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2},
                    new Dog {Name = "Jack", Age = 17}
                };

            foreach (Dog d in myDogs)
            {
                Console.WriteLine(d);
                d.Age++;
            }

            // Compile Error: The name 'd' does not exist in the current context
            string someDog = d.Name;

#1,118 – foreach Works with Iterator Returned by yield

You can use the yield keyword in a method to implement an iterator.  The method in which it is defined returns an IEnumerable or IEnumerator.  The resulting iterator can be consumed using the foreach statement.

Below is an example of a method that returns an IEnumerable<T> which can then be iterated upon using a foreach statement.

        static IEnumerable<Dog> DogsWithKids(IEnumerable<Dog> dogList)
        {
            foreach (Dog d in dogList)
            {
                yield return d;
                yield return new Dog(d.Name + " Jr.",
                                     Math.Max(d.Age - 3, 1));
            }
        }

        static void Main(string[] args)
        {
            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2}
                };

            // Iterate through dogs w/offsprings
            foreach (Dog d in DogsWithKids(myDogs))
                Console.WriteLine(d);

            Console.ReadLine();
        }

The result is a sequence with twice as many elements as the original List<T>.

1118-001

#1,117 – foreach Requires IEnumerable Implementation

The foreach statement works on an object that implements IEnumerable<T> or IEnumerable.  It also works on an object whose type has a public GetEnumerator method that returns an IEnumerator<T> or IEnumerator.

Below, we’ve defined a new class that implements IEnumerable<T>.

    public class DogPack : IEnumerable<Dog>
    {
        private List<Dog> thePack;

        public DogPack()
        {
            thePack = new List<Dog>();
        }

        public void Add(Dog d)
        {
            thePack.Add(d);
        }

        // Remove arbitrary dog
        public void Cull()
        {
            if (thePack.Count == 0)
                return;

            if (thePack.Count == 1)
                thePack.RemoveAt(0);
            else
            {
                Random rnd1 = new Random();
                int indRemove = rnd1.Next(thePack.Count);
                thePack.RemoveAt(indRemove);
            }
        }

        // IEnumerable<T> implementation

        public IEnumerator<Dog> GetEnumerator()
        {
            return thePack.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

We can now use foreach to iterate on an instance of this class.

            DogPack pack = new DogPack();
            pack.Add(new Dog("Lassie", 8));
            pack.Add(new Dog("Shep", 12));
            pack.Add(new Dog("Kirby", 10));
            pack.Add(new Dog("Jack", 15));
            pack.Cull();

            // Who's left?
            foreach (Dog d in pack)
                Console.WriteLine(d);

1117-001

#1,116 – Iterating Through a String Using the foreach Statement

You can iterate through the individual characters in a string using the foreach statement.  The iteration variable is of type char and is set consecutively to each character within the string as the foreach statement executes.

            string secret = "Kint is Keyser Soze";

            StringBuilder sbObfuscate = new StringBuilder();

            foreach (char c in secret)
                sbObfuscate.Append((char)(c + 3));

            Console.WriteLine(sbObfuscate);

1116-001

#1,115 – Iterating Through a Collection Using the foreach Statement

In the same way that you can iterate through an array using foreach, you can iterate through the elements of a collection one at a time.  You do this by writing a loop–a block of code that is executed more than once, executing once for each element in the collection. This is done using the C# foreach statement.

The foreach statement declares a variable local to the loop of the same type of the elements in the collection.  This variable takes on the value of each element in the collection.

            List<Dog> myDogs = new List<Dog>
            {
                new Dog {Name = "Kirby", Age = 15},
                new Dog {Name = "Jack", Age = 17},
                new Dog {Name = "Ruby", Age = 2}
            };

            // Output using overridden ToString() method
            foreach (Dog d in myDogs)
                Console.WriteLine(d);
1115-001