C# Generic Comparer
April 17th, 2008This morning I ran into a situation where i need to sort an array of ServiceController before binding into a combobox. So I looked around and I found Array.Sort (or List
private class ServiceControllerSort : IComparer<ServiceController> { public int Compare(ServiceController x, ServiceController y) { return string.Compare(x.DisplayName, y.DisplayName, true); } }
Now what? What if next time I want to sort on my ExtendedServiceController class (as if there is necessity to do one)? I will have more and more IComparer implementations. I decided to explore further and this page says it all. Took the code, clean it up and woots, I have a generic comparison class that is usable for almost all types.
/// <summary> /// Custom sorter based on property /// </summary> /// <typeparam name="T">Target Type</typeparam> public class ExtSortComparer<T>: IComparer<T> { private ListSortDirection _sortDirection = ListSortDirection.Ascending; private PropertyDescriptor _targetPropDescriptor; /// <summary> /// Constructor /// </summary> public ExtSortComparer() { } /// <summary> /// Constructor /// </summary> /// <param name="PropertyName">Name of property to sort on. Case sensitive.</param> public ExtSortComparer(string PropertyName) { _targetPropDescriptor = TypeDescriptor.GetProperties(typeof(T))[PropertyName]; } /// <summary> /// Constructor /// </summary> /// <param name="PropertyName">Name of property to sort on. Case sensitive.</param> /// <param name="SortDirection">Sort direction</param> public ExtSortComparer(string PropertyName, ListSortDirection SortDirection) : this(PropertyName) { _sortDirection = SortDirection; } /// <summary> /// Constructor /// </summary> /// <param name="TargetProperty">Descriptor of property to sort on</param> public ExtSortComparer(PropertyDescriptor TargetProperty) { _targetPropDescriptor = TargetProperty; } /// <summary> /// Constructor /// </summary> /// <param name="TargetProperty">Descriptor of property to sort on</param> /// <param name="SortDirection">Sort direction</param> public ExtSortComparer(PropertyDescriptor TargetProperty, ListSortDirection SortDirection) { _targetPropDescriptor = TargetProperty; _sortDirection = SortDirection; } /// <summary> /// Compare two given object /// </summary> /// <param name="x">Object A</param> /// <param name="y">Object B</param> /// <returns>Result of comparison</returns> public int Compare(T x, T y) { //ensure there is proper property description if (_targetPropDescriptor != null) { int intRetValue = _CompareValues(_targetPropDescriptor.GetValue(x), _targetPropDescriptor.GetValue(y)); //reverse the sorting if descending if (_sortDirection == ListSortDirection.Descending) return intRetValue * -1; return intRetValue; //return the result } return 0; //return neutral if insufficient information to sort } /// <summary> /// Compare values of target property /// </summary> /// <param name="ValueX">Value of property (Object A)</param> /// <param name="ValueY">Value of property (Object B)</param> /// <returns>Result of comparison</returns> private int _CompareValues(object ValueX, object ValueY) { if (ValueX is IComparable) //if X can be compared return ((IComparable)ValueX).CompareTo(ValueY); if (ValueY is IComparable) //else if Y can be compared return ((IComparable)ValueY).CompareTo(ValueX); //when both can't be compared, resort to string value. return ValueX.ToString().CompareTo(ValueY.ToString()); } }
The comments should explain what is happening internally. Another good addition to my common library! If you have any thoughts, shoot!