This isn't so much a new or very difficult thing, but it's something I've happened to come across twice recently, and I've needed to dig up the example code both times, so thought I'd add it to my blog for future reference.
Basically, I'm getting much more interested in dealing with object arrays rather than DataSets even in smaller projects. I feel like I have more control over certain things with object arrays, like business logic and customising properties. Now one of my projects was .net 2.0 so I used the generic List<> which was quite nicely put together, but my other project is a 1.1 project, so needed a slightly more outdated method.
I'll explain that one here, and probably add a note about the List<> way to do the same (plus more) next time.
Setting up the object array
For a very basic example I've got a class with a couple of fields in it for an Mp3 list:
public class Mp3Class {
private string _Artist;
private string _Song;
private int _Ranking;
public string Artist { get { return _Artist;} set {_Artist = value;}}
public string Song { get { return _Song;} set {_Song = value;}}
public int Ranking { get { return _Ranking;} set {_Ranking = value;}}
public Mp3Class (string Artist, string Song, int Ranking)
{
_Artist = Artist; _Song = Song; _Ranking = Ranking;
}
}
A basic example to get some data into this would be:
Mp3Class[] mp3s = new Mp3Class[5];
mp3s[0] = new Mp3Class("Cave", "Ship Song", 9);
mp3s[1] = new Mp3Class("Nirvana", "Smells like teen spirit", 3);
mp3s[2] = new Mp3Class("Sonic Youth", "100%", 1);
mp3s[3] = new Mp3Class("Cave", "Red right hand", 4);
mp3s[4] = new Mp3Class("Nirvana", "Heart shaped box", 7);
The Array class
So the thing you really need to get your head around working with arrays of objects is the Array class. It's very similar to working with List<>, but missing a few features. For simple arrays, things like IndexOf, Sort and even BinarySearch can be straight forward, but with object arrays a little more work is needed, but fortunately not too much.
Array.Sort
For sorting our class, there is one big thing that makes it more difficult. Which property do you sort on? In this case all are valid, as you may be ordering by artist, by ranking or even by song, but that means we need to implement another class to help us out. The IComparer interface gives us the ability to sort things how we wish using our objects. Basically, if we want to sort this list by Artist, we can implement an IComparer class which compares the Artist string, and Sort will do the rest, or if we want to sort by Ranking, we can compare the ranking numbers and Sort will do the rest. Here are those two examples:
public class ArtistCompareClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = String.Compare((x as Mp3Class).Artist, (y as Mp3Class).Artist, true);
return RetVal;
}
}
public class RankingCompareClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = (x as Mp3Class).Ranking - (x as Mp3Class).Ranking;
return RetVal;
}
}
The ArtistCompareClass cheats by using String.Compare (with case insensitivity). IComparer.Compare is simply looking for a negative if the first object should be ordered earlier, 0 if they are the same and a positive number if the 2nd object should be ordered earlier. Passing this object to Array.Sort will sort the array alphabetically by Artist.
The RankingCompareClass implements the same IComparer.Compare, so again, if the first Ranking is smaller it returns a negative, if they are the same a 0, if the 2nd Ranking is smaller a positive. This will order the object array by Ranking.
The call to sort the array will look like this:
Array.Sort(mp3s, new RankingCompareClass());
You now have the mp3s ordered by Ranking.
Array.BinarySearch
The BinarySearch as the name suggests searches the array using the same IComparer (or at least can do it this way). So again IComparer helps us search through an array of objects, when the language would otherwise have no idea of what it's searching for.
Note: Remember these key things when using a BinarySearch:
- You must sort by the IComparer before using BinarySearch
- It won't work (100%) if your "key" is not unique
- If the result is negative, you can do a bitwise operation to see the closest match
- If you are only searching a subset of the array, it will still return the item in the entire array that's a match.
Here are a couple of examples. I'll give you another IComparer which will help do "real" searches easier. In this case we'll send through the ranking as the 2nd parameter rather than a full object. As you can imagine if someone wanted to search for the song with ranking number 5, it's easier to pass through 5 than new Mp3Class("", "", 5):
public class RankingCompareValueClass : IComparer
{
int IComparer.Compare(object x, object y)
{
int RetVal = (x as Mp3Class).Ranking - (int)y;
return RetVal;
}
}
To find the object which matches a search with a ranking of 4 (MatchingObject is 2, which is the 3rd object in the array):
Array.Sort(mp3s, new RankingCompareClass());
int MatchingObject = Array.BinarySearch(mp3s, 5, new RankingCompareValueClass());
MessageBox.Show(mp3s[MatchingObject].Artist + " - " + mp3s[MatchingObject].Song);
If the user tried to search for a ranking of 5, we could take them to the next closest match (MatchingObject is 3, which is the 4th object in the array):
Array.Sort(mp3s, new RankingCompareClass());
int MatchingObject = Array.BinarySearch(mp3s, 5, new RankingCompareValueClass());
if (MatchingObject < matchingobject =" ~MatchingObject;">" - " + mp3s[MatchingObject].Song);
That's about it. It's worth pointing out that List<> does most of this stuff plus more, and is slightly easier to use, so I'd tend to use that for any 2.0+ projects.