To demonstrate the use of collections, Iím going to create a console application that
simulates a shopping cart.
First, letís create a class called Item. These items will be anything that you might
add to the shopping cart. Iíll give it a couple of simple properties: a title and a
price.
Just to make it easier to display, letís override the ToString method. Weíll just
show the title if somebody calls ToString. Actually, letís show both the title and the
price.
Now Iíll create a constructor that defines both the title and the price.
Thatís enough for my Item. Of course, we should be more specific hereóif somebody
is buying a book, we should have a separate class for a book because books have unique
properties such as an author. If somebody is buying a CD, we should be able to define
the artist.
Iím going to derive classes for both books and CDs from the Item class. The reason for
doing that will be more obvious as we go along, but basically it allows us to treat both books
and CDs as the same class, because weíll be able to deal with the common base class
the properties contained within the base class.
So, for the book Iíll define the ISBN, which is a code that uniquely defines the book.
Iíll also give it a custom constructor that not only defines the title and price that
are in the base class, but also the ISBN.
And I will quickly also define a CD based on the Item class with the unique Artist property.
To do that, Iím also going to need to define a default constructor for Item.
OK, that should do it. Now Iíll be able to get into the meat of the application, which
involves adding instances of books or CDs to an array, and then displaying that array
or sorting that array. So, the first class Iíll work with is an ArrayList that requires
me to add the System.Collections namespace.
Here, Iíll define an instance of ArrayList and I will simply go through and manually
add a few different items. Youíll see this wouldnít be efficient to do it in the real
world, but for the sake of this example, it will keep it simple. To do that, Iím also
going to need to define a default constructor for Item. That should do it.
Now Iíll be able to get into the meat of the application, which involves adding instances
of books or CDs to an array, and then displaying that array or sorting that array. The first
class Iíll work with is ArrayList. That requires me to add the System.Collections namespace.
Here, Iíll define an instance of ArrayList.
Iíll simply go through and manually add a few different items. Youíll see this wouldnít
be efficient to do it in the real world, but for the sake of this example, itíll keep
it simple. Weíll just call the add method, and then create a new instance of each item.
Iíll use one of my books, the Windows Vista Resource Kit, and call the book constructor
which requires typing the ISBN (no, I donít have this memorized). And the Windows 7 Resource
KitÖ
To demonstrate that we can add different types of objects to an ArrayList, Iím going to
create a couple of CDs, too. Iím going to use the standard Microsoft fictitious names
because I donít have any CDs released.
With the Items ArrayList filled with different types of items, Iím going to create a method
that simply displays them to the console. Iíll call it ShowShoppingCart. Notice that
it takes an instance of ArrayList, so it doesnít care about the contents of the ArrayList.
Itís simply an instance of ArrayList.
Iíll create a for-each loop to iterate through the objects in the ArrayList. Notice that
I donít need to say ìfor-each-bookî or ìfor-each-CDî in the ArrayList. I simply
need to use the base class that they have in common, and Iíll be able to access the
properties that are available in the base class. Iím just displaying them to the console,
so a simple ToString will suffice. Iím going to add a method to the Main method to pause
the console when I run it.
And, of course, I need to call the ShowShoppingCart method. This is ready to run and weíll be
able to view the contents of the shopping cart. Notice that the sequence is exactly
the sequence that I ordered them in; theyíre not sorted in any way. Weíll do that next.
So, ArrayList has a method called Sort that we can call. Letís just do that and see what
happens. We get an error message saying that it couldnít compare two elements of the array.
If you want to sort something, you have to implement the IComparable interface. Letís
go and do that now.
To do that, weíll just inherit the IComparable interface. C# will make it easy for us to
implement the interface. Down here, it added the structure for the method, and I just need
to overwrite the default constructor. So, CompareTo is really easy to implement. All
CompareTo wants to know is which of two instances comes first if you sort them. So, we could
sort them by price or title. For now, letís make the default sorting method by title.
So, we can do this all in one line. All I need to do is to access the title property
and then call its default comparer. Title is a String, and String has the CompareTo
method already implemented. So, Iíll call that and compare that to the object that is
already compared to. Iíll let the String implementation see which of those comes first.
You can see that thereís an existing instance. The CompareTo method accepts an object class,
which is an object of the same type, and I need to return whichever comes first. So,
Iím calling the Title propertyís implementation of CompareTo, and passing it the exact same
parameter that I was passed, but cast to an Item, and then the title property of that
object. It will return whichever one comes first, and then my return string passes that
up to the original caller. This will be enough for the Array.Sort method to work. You can
see here that Contoso music comes first because it starts with a C, followed by Fabrikam Music.
In a shopping cart, some people want to see things sorted by price. That gets a little
more complicated. If you want to do something other than the default comparer, you can create
your own IComparer implementation. Letís do that now to allow people to sort things
in the Items array by price.
Weíll call it SortItemsByPrice, and we want IComparer rather than IComparable. Iíll implement
the standard interface here. Now, the Compare method is not an instance of the class being
comparedóitís its own class. So, it actually receives two different objects. Weíre returning
an integer indicating which of the two comes first.
The implementation is still going to be pretty easy. First, Iím going to cast the two objects
to the correct item. Then, Iím going to call the implementation from the base property
class. So, for my return, Iím simply going to access Price and call the CompareTo method.
Iím also going to alter one of these pricesóletís say that thereís a sale on the Windows Vista
Resource Kit, so weíre going to lower the price of that.
The Sort method can take an IComparer instance, so Iíll pass it the SortItemByPrice class.
First, I need to create an instance of it. Then, I can pass it.
Here it isóyou can see that it correctly sorted the ArrayList by Price. So, the ArrayList
class is my favorite class for general array usage. Sometimes, you need more specialized
uses. Letís say youíre creating an array that keeps track of orders different customers
have placed so that you could ship them in order from first received to last received.
The .NET Framework provide the Queue class to do that.
Iím going to remove my ArrayList implementation and replace it with a Queue. Otherwise, it
basically works the same. Queue doesnít have an Add method, instead it has Queue. IT does
basically the same thing as Add, it just has a different name. You generally donít sort
items in a Queue, because after all, you want to work with them in the order they came in.
Queue is first-in, first-out, which is perfect for shipping or serving customers. So, I need
to change my ShowShoppingCart to work with a Queue instead. Generally, you wouldnít
work with a for-each loop with a Queue. Instead, what youíll do is call the DeQueue method.
So, instead of a for-each Loop, Iíll create a while loop that iterates through all the
items in the Queue.
When you DeQueue something, itís removed from the Array. So, calling DeQueue is like
accessing the item and removing it at the same time. As long as there are more than
one item in the Queue, weíll keep iterating through the While loop. Here, Iíll extract
the first item from the Queue and Iíll write it to the console so we can see it.
So, letís give this a shot. As you can see, it displays the items in the exact order that
I added them. The first one added was the Vista Resource Kit, so that was the first
one displayedófirst-in, first-out.
The .NET Framework provides another, very similar, but kind of opposite, collection
type called Stack. People who have done low-level programming already know the way stacks work:
theyíre a last-in, first-out type of collection. Instead of calling EnQueue, you call Push.
You Push things onto a stack, and you EnQueue them onto a Queue. In the development world,
Stacks are used to keep track of methods that call each other. So, if Method A calls Method
B and then Method B calls Method C, once Method C completes, execution needs to return to
Method B, which is the last item added to the stack. After Method B completes, execution
needs to return to Method (the last item added to the stack). You wouldnít want a first-in,
first-out method, because Method A wouldnít be ready after Method C completes.
In the real world, you might use a Stack to determine which items in an inventory should
be removed first. For example, if you had 50 copies of a book in your warehouse, all
stacked on top of each other, and you wanted to determine which one should go out first,
you would take the top one off of the stack even though it was the last one added.
As before, I need to update the ShoppingCart to work with a Stack instead. Instead of calling
DeQueue, I want to call PopóPop removes the item from the stack. Weíll run this, and
what weíll see is the items in the exact opposite order. So here, Fabrikam was the
last item added to the stack, but itís the first item to come off. If you ever do need
to view an item in the stack without removing it, you can use the Peek method. Itís the
same as Pop, but it returns an item without removing it. If I were to add this now, it
would just cycle forever.