You can take this a step further and create a Comparer class that uses
reflection to look at the properties of the object it's comparing to do
the compare. Then you get rid of the switch statement and use the same
comparer class for any object. Here's an example:
/// <summary>
/// The PropComparer class is a generic comparer. It takes a
PropertyDescriptor
/// and compares two of whatever type the descriptor points to.
/// </summary>
public class PropComparer : IComparer
{
private PropertyDescriptor sortProperty;
private ListSortDirection sortDirection;
/// <summary>
/// Creates a new PropComparer that will use the specified
property and direction.
/// </summary>
/// <param name="initProperty">The property to use.</param>
/// <param name="initDirection">The sort direction to use.</param>
public PropComparer(PropertyDescriptor initProperty,
ListSortDirection initDirection)
{
sortProperty = initProperty;
sortDirection = initDirection;
}
/// <summary>
/// Compares two objects based upon the passed properties.
/// </summary>
/// <param name="x">The property of object X.</param>
/// <param name="y">The property of object Y.</param>
/// <returns></returns>
public int Compare(object x, object y)
{
int result;
IComparable cmpIf;
object propertyX;
object propertyY;
//
// Get the actual objects that we are comparing
// These a basically fields from the X and Y objects
//
propertyX = sortProperty.GetValue(x);
propertyY = sortProperty.GetValue(y);
//
// Deal with one or both being null
//
if ((propertyX == null) && (propertyY == null))
{
result = 0;
}
else if (propertyX == null)
{
result = -1;
}
else if (propertyY == null)
{
result = 1;
}
else
{
//
// Get the IComparable interface
// This will throw an exception if the object isn't
comparable
//
cmpIf = (IComparable)propertyX;
//
// Compare X.Property and Y.Property
//
result = cmpIf.CompareTo(propertyY);
}
//
// If they are equal, see if we can compare the parent
objects
//
if (result == 0)
{
//
// Get the IComparable interface from the X object
// This won't throw an exception if IComparable isn't
supported
//
cmpIf = x as IComparable;
if (cmpIf != null)
{
//
// Compare X and Y
//
result = cmpIf.CompareTo(y);
}
}
//
// If the direction is descending, reverse the sign
//
if (sortDirection == ListSortDirection.Descending)
{
result = -result;
}
return result;
}
}
and here is how you would use the PropComparer:
//
// Get a collection of property descriptors for your object
//
PropertyDescriptorCollection pdc =
TypeDescriptor.GetProperties(typeof(YourClass));
//
// Sort your list with the PropComparer
//
TheList.Sort(new PropComparer(pdc["FirstName"],
ListSortDirection.Ascending));
Reflection is one of the coolest features of .NET.
John Vottero
RCS said:
Chris, John and James,
This is just what I needed - now I'm well underway!! this works just
about as I wanted it to. Thanks very, very much!!
and Chris, here's that code translated into C# and it works like a
charm:
public class FileObjectComparer : IComparer
{
private string _compareField = "";
public FileObjectComparer(string comparefield)
{
_compareField = comparefield;
}
public int Compare(object x, object y)
{
switch (_compareField)
{
case "FileName":
{
return (x as FileObject).FileName.CompareTo((y as
FileObject).FileName);
break;
}
case "FileSize":
{
return (x as FileObject).FileSize.CompareTo((y as
FileObject).FileSize);
break;
}
default:
{
return (x as FileObject).FileName.CompareTo((y as
FileObject).FileName);
break;
}
}
}
}
Inside that function, is that another User object being sent in? And
should
I do something like this?
User objUserFromOutside = (obj as User);
if ( this.FirstName > objUserFromOutside.FirstName)
return 1;
else
{
if ( this.FirstName == objUserFromOutside.FirstName)
return 0;
else
return -1;
}
Yes, that looks correct.
If so - then how would I handle a sort of different fields (like
lastname,
address, city, etc)???? Thanks again
For that, you would probably have to use a class that implements
IComparer instead. Then add a constructor to that class that indicates
the field to compare against. Something like this (watch for typos):
Public Class MyComparer
Implements IComparer
Private _compareField As String
Public Sub New(ByVal comparefield As String)
_compareField = comparefield
End Sub
Public Function Compare(ByVal x As Object, ByVal y As Object) As
Integer Implements System.Collections.IComparer.Compare
Select Case _compareField
Case "FieldA"
'Compare Logic for fieldA
Case "FieldB"
'Compare Logic for fieldB
Case "FieldC"
'Compare Logic for fieldC
Case Else
'Default compare logic
End Select
End Function
End Class
Then you could call it like this:
Dim al As New ArrayList
'populate the arraylist here somehow
'Sort on FieldB
al.Sort(New MyComparer("FieldB"))