#1,123 – Using foreach to Iterate on a Multidimensional Array

You can use the foreach statement to iterate through all elements in a multidimensional array.  The elements are iterated in a row-major order.  That is, all elements in the first row are enumerated, followed by the second row, etc.

            // 2-dimensional array
            string[,] twoByThree = new string[2, 3];

            // Populate with standard for loop
            for (int row = 0; row < 2; row++)
                for (int col = 0; col < 3; col++)
                    twoByThree[row, col] = string.Format("{0}/{1}", row + 1, col + 1);

            // Iterate using foreach
            foreach (string s in twoByThree)
                Console.WriteLine(s);

1123-001

#778 – A struct Isn’t Mutable When Used in a Collection

struct is normally mutable, i.e. you can modify the values of its members directly.

However, if a struct is used in a collection class, like a List<T>, you can’t modify its members.  Referencing the item by indexing into the collection returns a copy of the struct, which you can’t modify.  To change an item in the list, you need to create a new instance of the struct.

            List<DogCollarInfo> collarList = new List<DogCollarInfo>();

            // Create a few instances of struct and add to list
            collarList.Add(new DogCollarInfo(0.5, 14.0));
            collarList.Add(new DogCollarInfo(0.3, 12.0));

            // Compile-time error: Can't modify '...' because it's not a variable
            collarList[1].Length = 22.0;

            // Do this instead
            collarList[1] = new DogCollarInfo(collarList[1].Width, 22.0);

If you store the structs in an array, then you can change the value of one of the struct’s members.

            DogCollarInfo[] arr = new DogCollarInfo[2];
            arr[0] = new DogCollarInfo(0.5, 14.0);
            arr[0].Length = 5.0;  // OK

#774 – Passing an Array as an out Parameter

Like other reference types, you can use an array as an output parameter, using the out keyword.  The out keyword indicates that you must assign a value to the array before returning from the method.  Also, within the method, you cannot reference the array parameter before you assign a new value to it.

        static int FindFibsThrough(int numFibs, out int[] fibs)
        {
            // Can't reference element of array
            //int i = fibs[0];

            // Can't assign to element of array
            //fibs[0] = 12;

            if (numFibs < 2)
                throw new Exception("Must return at least 2 numbers in sequence");

            // Must assign new value to array before we return
            fibs = new int[numFibs];

            fibs[0] = 0;
            fibs[1] = 1;
            int sum = 1;

            for (int i = 2; i < numFibs; i++)
            {
                fibs[i] = fibs[i - 1] + fibs[i - 2];
                sum += fibs[i];
            }

            return sum;
        }

You must also use the out keyword when calling the method.

            int[] myFibs;
            int sum = FindFibsThrough(10, out myFibs);

774-001

#650 – Creating an Array of Anonymously-Typed Objects

An anonymous type is a temporary data type that is inferred based on the data that you include in an object initializer.  In addition to creating a single anonymously-typed object with an object initializer, you can also create an array of objects.

            var movies = new[] {
                new { Title = "North By Northwest", Year = 1959, Director = "Alfred Hitchcock" },
                new { Title = "Zelig", Year = 1983, Director = "Woody Allen" },
                new { Title = "King Kong", Year = 2005, Director = "Peter Jackson" }};

With this declaration, you end up with an array of anonymously-typed objects, each of which has the properties Title, Year, and Direction.

Note that this implicitly-typed array must contain elements of the same type, so each element must have the exact  same set of properties.

#600 – Reversing the Elements in an Array

You can use the static Array.Reverse method to reverse the order of elements in an array.  This modifies the contents of the array that you pass to Array.Reverse.

            int[] someNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            DumpArrayContents(someNumbers);

            // Reverse the elements using Array.Reverse
            Array.Reverse(someNumbers);
            DumpArrayContents(someNumbers);

Note that this Reverse method is different from the IEnumerable<int>.Reverse method, which does not modify the contents of the array, but just returns a reversed sequence.

// IEnumerable<int>.Reverse
int[] moreNumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> reversedNums = moreNumbers.Reverse();
DumpArrayContents(moreNumbers);
DumpArrayContents(reversedNums);

#597 – Returning an Array from a Method

You can return an array from a method just like you can return any other reference-typed object from a method.  The array will be instantiated within the method and a reference to the new object is what is returned to the calling code.

Assume that we have a method declared like this in a Dog class:

public string[] FavoriteToys()

We can then call this method as follows:

            Dog kirby = new Dog("Kirby", 15);

            string[] favToys = kirby.FavoriteToys();

            foreach (string toy in favToys)
                Console.WriteLine(toy);


We could also just use the method call in the body of the foreach loop:

            foreach (string toy in kirby.FavoriteToys())
                Console.WriteLine(toy);

#572 – Why Array Covariance Is Called Covariance

Array covariance in C# allows you to assign an array of instances of a derived class to a variable whose type is an array of instances of the base class.

Dog[] dogs = hounds;     // Where hounds is Hound[] and Hound is subclass of Dog

Covariance says that the ordering of two elements in a set is preserved after transforming each by the same function.

With array covariance, we can think of the “ordering” as being the fact that the subtype is narrower than the base class, which means that the assignment is allowed due to assignment compatibility.

The covariant function being applied to each type is to create an array of that type.  This “function”, an array of a type, is then covariant because if type T is narrower than type U, then T[] is also narrower than U[], preserving assignment compatibility.