If you are writing a .NET application you may be tempted to use DataSets to
represent relational data in your application. There are any number of good
reasons not to use DataSets and even more reasons you may encounter (especially
when integrating with systems you cannot control) where DataSets are not an
option. An excellent alternative is a Custom Type.
When I implement Custom Types in a system to represent my data I tend to follow
a couple of guidlines:
And, yes, my Property doesn't do much, but its there mostly for run-time
binding.
Using DataView.Sort its very easy to use code already in the runtime to sort
DataRows. With Custom Types however there is no readily apparent built in
solution. Dig slightly beneath the surface and you will find the
IComparer interface and the ArrayList.Sort(IComparer).
This, then, is one solution, but how can you implement this model without very
large if/then statements that are specific to a Type? I would like to:
The solution is easy using two excellent .NET features: Delegates and
Reflection. Delegates will allow me to use different comparison functions
dependent upon the Type of the field I want to compare; Reflection makes it
easy to identify metadata about classes at runtime. For now supporting int,
String, Date, and double types will suffice for most needs. Here is my Type
Comparer.
using System;
using
System.Collections;
using
System.Reflection;
namespace
damonpaynedotcom.Types
{
///
<summary>
/// Make it
easy to Sort Custom Types
///
</summary>
public class TypeComparer : IComparer
{
private delegate int
DoCompare(object x, object y);
private DoCompare
_compareMethod;
private PropertyInfo
_propInfo;
private Hashtable
_methods;
private bool _caseSensitive;
private string _sortProperty;
public TypeComparer(string propertyName, Type objectType)
{
_caseSensitive = true;
_sortProperty = propertyName;
_methods = BuildSortMethods();
_propInfo = objectType.GetProperty(_sortProperty);
if (null == _propInfo)
{
throw new ArgumentException(string.Format("Type {0} does not have a Property
'{1}'", new Object[] {objectType.ToString(),
propertyName}));
}
_compareMethod =
(DoCompare)_methods[_propInfo.PropertyType];
if (null == _compareMethod)
{
throw new ArgumentException( string.Format("Type not supported: {0}",
_propInfo.PropertyType) );
}
}
protected Hashtable BuildSortMethods()
{
Hashtable ht = new
Hashtable();
ht.Add(typeof(int), new
DoCompare(CompareInt));
ht.Add(typeof(double), new
DoCompare(CompareDouble));
ht.Add(typeof(string), new
DoCompare(CompareString));
ht.Add(typeof(DateTime), new DoCompare(CompareDate));
return ht;
}
public bool CaseSensitive
{
get{return _caseSensitive;}
set{_caseSensitive = value;}
}
protected int CompareInt(object x, object y)
{
int xInt = (int)x;
int yInt = (int)y;
return
xInt.CompareTo(yInt);
}
protected int CompareDouble(object x, object
y)
{
double xDouble = (double)x;
double yDouble = (double)y;
return
xDouble.CompareTo(yDouble);
}
protected int CompareDate(object x, object y)
{
DateTime xDate = (DateTime)x;
DateTime yDate = (DateTime)y;
return
xDate.CompareTo(yDate);
}
protected int CompareString(object x, object y)
{
string xString = (string)x;
string yString = (string)y;
if (!CaseSensitive)
{
xString = xString.ToUpper();
yString = yString.ToUpper();
}
return
xString.CompareTo(yString);
}
#region
IComparer Members
public int Compare(object
x, object y)
{
object xVal = _propInfo.GetValue(x,
null);
object yVal = _propInfo.GetValue(y,
null);
return _compareMethod(xVal,
yVal);
}
#endregion
}
}
If the need ever arises, I may experiment with algorithms for multiple-level
sort or sorting based on non-primative types. I also need to work a little bid on the code-formatting styles!