![]() |
Languages »
C# »
Generics
Intermediate
License: The Code Project Open License (CPOL)
Sorting using IComparer classes (including Generics)By Jeff BramlettMethodology demonstration for sorting collections by the item class properties or methods. |
C#.NET 2.0, Win2K, WinXPVS2005, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||

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.
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
{
/// <summary>
/// Reflection based, Generic Comparer
/// class for in-line or instance based Sorting
/// </summary>
/// <example>
/// List<DataObject> array = new List<DataObject>();
///
/// ... Code to populate list ...
///
/// array.sort(new GenericComparer<DataObject>("ID", "asc", null));
///
/// or
///
/// GenericComparer genericComparer =
/// new GenericComparer<DataObject>();
/// genericComparer.MemberName = "ID";
/// genericComparer.SortOrder = "asc";
///
/// array.sort(genericComparer);
/// </example>
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
/// <summary>
/// Default constructor for use in instances.
/// </summary>
public GenericComparer()
{
}
/// <summary>
/// Constructor for in-line instantiation
/// </summary>
/// <param name="memberName">string of the member name to use for comparison
/// can be either a method name or a property.
/// </param>
/// <param name="sortOrder">string of the sort order (case independent).
/// "ASC" for ascending order or anyting else for descending order</param>
/// <param name="methodParameters">object array
/// of parameters to use for method, null otherwise.</param>
public GenericComparer(string memberName, string sortOrder,
List<object> methodParameters)
{
this.memberName = memberName;
this.sortOrder = sortOrder;
this.methodParameters = methodParameters;
GetReflected();
}
#endregion
#region Private methods
/// <summary>
/// Sets the global field, propertyInfo
/// and/or memberInfo using the underlying Type
/// </summary>
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.");
}
}
/// <summary>
/// Return an IComparable for use in the Compare method
/// </summary>
/// <param name="obj">object to get IComparable from</param>
/// <returns>IComparable for this object</returns>
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
/// <summary>
/// Implementing method for IComparer
/// </summary>
/// <param name="objOne">Object to compare from</param>
/// <param name="objTwo">Object to compare to</param>
/// <returns>int of the comparison, or 0 if equal</returns>
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
}
}
The Generic Comparer and the General Comparer can be re-used in your projects "as is".
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.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 23 Jun 2006 Editor: Smitha Vijayan |
Copyright 2006 by Jeff Bramlett Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |