Comparing Objects in VB.NET
using IComparer
Any VB6 programmer that's come over to VB.NET has no doubt fallen in love with it. So many things that were brutally painful to do in VB6 are a piece of cake in .NET. Obviously entire books have been written on this subject, but I'd like to discuss one of them....Interfaces.
If you aren't familiar with them, Interfaces are a code contract that your classes must fulfill if you choose to implement them. If you come from a C/C++ background (you know doubt have mastered this concept), you probably remember breaking up your classes into a header and a body, thereby seperating your class description from its implementation. Interfaces in .NET aren't exactly the same, however they ultimately get you to a point where you can decouple a description from its implementation.
Let's say that you have two objects called Person with three properties, FirstName, LastName and DOB...
Option Strict On
Option Explicit On
Public Class Person
Private _FirstName As String
Private _LastName As String
Private _DOB As Date
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set (ByVal Value as String)
_FirstName = Value
End Set
End Property
Public Property LastName() As String
Get
Return _LastName
End Get
Set (ByVal Value as String)
_LastName = Value
End Set
End Property
Public Property DOB() As Date
Get
Return _DOB
End Get
Set (ByVal Value as Date)
_DOB = Value
End Set
End Property
End Class |
Ok, so somewhere in my code, I create to Person objects, Bill Jones and Joe Bills.
Dim Person1 as New Person()
Person1.FirstName = "Bill"
Person1.LastName = "Jones"
Person1.DOB = "01/01/1980"
Dim Person2 as New Person()
Person2.FirstName = "Joe"
Person2.LastName = "Bills"
Person2.DOB = "01/01/1990" |
Now, let's say we wanted to compare these two people. They aren't integers, they are complex objects (well, as complex as a three property class can be) so how do you compare them? Well, that's up to you. One method could be see who makes more money or who has more education but then we decide that would be kind of shallow. So we decide to compare them based on Age. One of the few things that I really dislike about VB.NET is lack of operator overloading, but even if we had it here, it wouldn't do us much good. So, how would we compare these? Well, we could do the old procedural way.... if Person2.DOB > Person1.DOB Then whatever. However, if we had to do this all over the place, we'd be writing a lot of code over and over and contrary to what many believe, writing a lot of code isn't the mark of a skilled programmer. Here's where interfaces come in and IComparer in particular. So, the first thing we need to do is modify out class definition:
Public Class Person should be changed to Public Class Person : Implements IComparer
Immediately we'll have a function shelled out for the only method which IComparer mandates, Compare. Now, the return type on this is an Integer, but to make things clear, let's create an Enumeration Stature, which has three members, FirstGreaterThanSecond, SecondGreaterThanFirst and Equal
Public Enum Stature As Integer
FirstGreaterThanSecond
SecondGreaterThanFirst
Equal
End Enum |
Let's implement our function now:
Public Function Compare(ByVal o1 As Object, ByVal o2 As Object) Implements IComparer.Compare
Dim p1 As Person
Dim p2 As Person
p1 = CType(o1, Person)
p2 = CType(o2, Person)
If p1.DOB > p2.DOB Then
Return Stature.FirstGreaterThanSecond
Else If
p1.DOB < p2.DOB Then<BR>
Return Stature.SecondGreaterThanFirst
End If
Else
Return Stature.Equal
End If
End Function |
That's about all there is to it to get it to work, but this example is obviously a bit silly because Persons are seldomly rated on Age alone. But you may have a more complex object that you need to be able to Sort for instance, and sort on multiple fields. In such a case, the ability to compare on different fields becomes increasingly important and as you can see, it wouldn't take much more code to come up with a much more sophisticated Compare algorithm. Another thing I'd recommend is the use of an Enumeration. Enum have two really great things going for them: 1) They are value types (and value types are good) 2) They show up in intellisense which makes your code much friendlier to users of your code. I did leave one important detail out of my code, but I did it intentionally so I can make a point. Notice that if you use the standard compare function, you are passing in two parameters of type Object. So, someone could have passed in an ArrayList and a Foo object and this code would have blown up. As such, YOU are the one in charge of the implementation and are responsible for EVERYTHING in it. All the Interface does is define a contract and make sure that you do something to fulfill it. It does nothing to ensure that your implementation is valid. I could have changed the Person type to Foo and pass in Two Foo objects and it would work. This is very important because you can pass in virtually anything and aren't even forced to compare objects of the type of the class you are implementing. So it gives you a lot of power, but with it, you have the power to shoot off your foot.