Introduction
I needed a methodology for sorting collections, by either properties or methods of the collection item class. I also needed to change the sort at runtime, and compare the performance of various IComparer
implementations. This demo project is the result of this research.
Using the code
The source code contains this IComparer
class implementation plus three others:
Generic Comparer - a class to be used for generic sorting of collection items based on a property or a method.
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
namespace SortingMethods
{
public class GenericComparer<T> : IComparer<T>
{
#region Fields
private string memberName = string.Empty;
private string sortOrder = string.Empty;
private List<object> methodParameters = new List<object>();
PropertyInfo propertyInfo = null;
MethodInfo methodInfo = null;
#endregion
#region Properties
public string MemberName
{
get
{
return memberName;
}
set
{
memberName = value;
GetReflected();
}
}
public string SortOrder
{
get
{
return sortOrder;
}
set
{
sortOrder = value;
}
}
public List<object> MethodParameters
{
get
{
return methodParameters;
}
}
#endregion
#region Ctors
public GenericComparer()
{
}
public GenericComparer(string memberName, string sortOrder,
List<object> methodParameters)
{
this.memberName = memberName;
this.sortOrder = sortOrder;
this.methodParameters = methodParameters;
GetReflected();
}
#endregion
#region Private methods
private void GetReflected()
{
Type[] underlyingTypes = this.GetType().GetGenericArguments();
Type thisUnderlyingtype = underlyingTypes[0];
MemberInfo[] mi = thisUnderlyingtype.GetMember(memberName);
if (mi.Length > 0)
{
if (mi[0].MemberType == MemberTypes.Property)
{
propertyInfo = thisUnderlyingtype.GetProperty(memberName);
}
else if (mi[0].MemberType == MemberTypes.Method)
{
Type[] signatureTypes = new Type[0];
if (methodParameters != null && methodParameters.Count > 0)
{
signatureTypes = new Type[methodParameters.Count];
for (int i = 0; i < methodParameters.Count; i++)
{
signatureTypes[i] = methodParameters[i].GetType();
}
methodInfo =
thisUnderlyingtype.GetMethod(memberName,
signatureTypes);
}
else
{
methodInfo =
thisUnderlyingtype.GetMethod(memberName,
signatureTypes);
}
}
else
{
throw new Exception("Member name: " + memberName +
" is not a Public Property or " +
"a Public Method in Type: " +
thisUnderlyingtype.Name + ".");
}
}
else
{
throw new Exception("Member name: " +
memberName + " not found.");
}
}
private IComparable GetComparable(T obj)
{
if (methodInfo != null)
{
return (IComparable)methodInfo.Invoke(obj,
methodParameters.ToArray());
}
else
{
return (IComparable)propertyInfo.GetValue(obj, null);
}
}
#endregion
#region IComparer Implementation
public int Compare(T objOne, T objTwo)
{
IComparable iComparable1 = GetComparable(objOne);
IComparable iComparable2 = GetComparable(objTwo);
if (sortOrder != null && sortOrder.ToUpper().Equals("ASC"))
{
return iComparable1.CompareTo(iComparable2);
}
else
{
return iComparable2.CompareTo(iComparable1);
}
}
#endregion
}
}
Points of interest
The Generic Comparer and the General Comparer can be re-used in your projects "as is".
Acknowledgment
Thanks to all who have contributed comments! I have recoded the GenericComparer
to create the ProgramInfo
and/or MethodInfo
objects in the constructor or when the MemberName
property is set. The GetReflected()
method uses Reflection to get the Type of the underlying object to get the PropertyInfo
and/or MethodInfo
.