A Few Things About Array Interfaces
Posted on January 21, 2007
One of the fun things about working with a big framework like .NET is that even after a few years of immersion in the technology, there are still fresh lessons to learn. So today, in the “I did NOT know that” department, I present a few interesting things about the humble array. The code snippets shown are part of a complete sample program that you can download here.
Arrays are enumerable
I did know this. Array implements IEnumerable, so you can iterate over the items in the array. There are two ways in C#. The direct way is to obtain an IEnumerator via IEnumerable.GetEnumerator(), and walk through the array:
IEnumerable enumerable = new Customer[] { bobSmith, johnDoe, johnGalt }; IEnumerator enumerator = enumerable.GetEnumerator(); while (enumerator.MoveNext()) { Customer c = (Customer)enumerator.Current; Console.WriteLine(c.ContactName); }
Of course, most of us would prefer the simpler foreach construct, which does the same thing with more syntactic finesse:
IEnumerable enumerable = new Customer[] { bobSmith, johnDoe, johnGalt }; foreach (Customer c in enumerable) { Console.WriteLine(c.ContactName); }
An Array is an ICollection
In fact, Array implements a number of collection interfaces. Almost all are explicit interface implementations, which means that we have to cast to the collection type before we can use the methods and properties of the collection interface.
After IEnumerable, ICollection is the most primitive interface. If we look at an array as an ICollection, we can find the number of array elements with the Count property (equivalent to Array.Length). We can also see that an array is not synchronized (thread-safe), but it does offer a SyncRoot object for thread synchronization. The SyncRoot object happens to be the array itself.
Customer[] customers = new Customer[] { bobSmith, johnDoe, johnGalt }; ICollection collection = customers; Console.WriteLine("Count = " + collection.Count.ToString()); Console.WriteLine("IsSynchronized: " + collection.IsSynchronized.ToString()); Console.WriteLine("SyncRoot: " + collection.SyncRoot == null ? "(null)" : collection.SyncRoot.ToString()); Console.WriteLine("SyncRoot == customers? " + (object.ReferenceEquals(collection.SyncRoot, customers) ? "Yes" : "No"));
An Array is an IList
Now things get interesting. The IsFixedSize property of IList returns true for an array, which makes sense. You have to declare an array with a specific size. However, Array does offers the Resize method, so is an array really fixed in size? The answer is yes – the Resize method really creates a new array of the specified size and changes the reference from the original array to the new array (that’s why the array parameter of Resize is a ref parameter).
The fixed size of Array has some other consequences. As an IList implementation, Array must support Add(), Clear(), Insert(), Remove(), and RemoveAt(). Because the size of the array cannot be changed, it doesn’t really make sense to add or delete items. All of these methods except Clear() throw NotSupportedException for this reason. Clear() does work, although it does not affect the size of the array – it simply sets the value of each array item to null (or the zero-bit equivalent for a value type array item).
Generic Interfaces
With the advent of .NET 2.0, generics were added to the framework, including generic versions of the collection interfaces. Thus we have IEnumerable
This is perhaps intuitive, as an array instance is strongly typed when it is declared. Array does in fact implement all of these generic interfaces. An array of Customer objects is an IEnumerable
As with the add/delete methods of IList, the corresponding methods of ICollection
The support of generic interfaces in Array is very convenient. it allows for easy initialization of generic collections with arrays:
Customer[] customers = new Customer[] { bobSmith, johnDoe, johnGalt }; // Constructors requiring IListcan use array of T. Collection collection = new Collection (customers); BindingList bindingList = new BindingList (customers); // Constructor requiring IEnumerable can use array of T. List list = new List (customers);
And of course, methods that return an IList
Who knew arrays were so cool?
Got something to say?