If you need to sort Lists (not ILists) of different classes without the need to create a seperate comparer class for all of them and still keep your entity classes clean (you don't want to implement IComparable), you can use the following (compatible with .NET 2.0):
public class DynamicComparer<T> : IComparer<T>
{
private Func<T, int> calculateFunc;
private int calculateMultiplier;
private Func<T, T, int> compareFunc;
public DynamicComparer(Func<T, int> calculateFunc, bool reverse = false)
{
if (calculateFunc == null)
{
throw new Exception("Delegate function 'calculateFunc' cannot be null.");
}
this.calculateFunc = calculateFunc;
this.calculateMultiplier = reverse ? -1 : 1;
this.compareFunc = null;
}
public DynamicComparer(Func<T, T, int> compareFunc)
{
if (calculateFunc == null)
{
throw new Exception("Delegate function 'compareFunc' cannot be null.");
}
this.calculateFunc = null;
this.compareFunc = compareFunc;
}
public int Compare(T x, T y)
{
if (calculateFunc != null)
{
return (calculateFunc(x) - calculateFunc(y)) * this.calculateMultiplier;
}
if (compareFunc != null)
{
return compareFunc(x, y);
}
throw new Exception("Compare not possible because neither a Compare or a Calculate function was specified.");
}
}
You'll also need the Func delegates if you're using .NET 2.0 (found on Replacing Func with delegates C#):
public delegate TResult Func<T, TResult>(T t);
public delegate TResult Func<T, U, TResult>(T t, U u);
Usage:
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty) // Ascending
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty, true) // Descending
Some simple unit testing:
[TestClass()]
public class DynamicComparerTU
{
[TestMethod()]
public void SortIntList()
{
// Arrange
dynamic myIntArray = new int[] {
4,
1,
9,
0,
4,
7
};
dynamic myIntList = new List<int>(myIntArray);
// Act
int temp = 0;
for (int write = 0; write <= myIntArray.Length - 1; write++)
{
for (int sort = 0; sort <= myIntArray.Length - 2; sort++)
{
if (myIntArray(sort) > myIntArray(sort + 1))
{
temp = myIntArray(sort + 1);
myIntArray(sort + 1) = myIntArray(sort);
myIntArray(sort) = temp;
}
}
}
myIntList.Sort(new DynamicComparer<int>(x => x));
// Assert
Assert.IsNotNull(myIntList);
Assert.AreEqual(myIntArray.Length, myIntList.Count);
for (int i = 0; i <= myIntArray.Length - 1; i++)
{
Assert.AreEqual(myIntArray(i), myIntList(i));
}
}
[TestMethod()]
public void SortStringListByLength()
{
// Arrange
dynamic myStringArray = new string[] {
"abcd",
"ab",
"abcde",
"a",
"abc"
};
dynamic myStringList = new List<string>(myStringArray);
// Act
myStringList.Sort(new DynamicComparer<string>(x => x.Length));
// Assert
Assert.IsNotNull(myStringList);
Assert.AreEqual(5, myStringList.Count);
Assert.AreEqual("a", myStringList(0));
Assert.AreEqual("ab", myStringList(1));
Assert.AreEqual("abc", myStringList(2));
Assert.AreEqual("abcd", myStringList(3));
Assert.AreEqual("abcde", myStringList(4));
}
[TestMethod()]
public void SortStringListByLengthDescending()
{
// Arrange
dynamic myStringArray = new string[] {
"abcd",
"ab",
"abcde",
"a",
"abc"
};
dynamic myStringList = new List<string>(myStringArray);
// Act
myStringList.Sort(new DynamicComparer<string>(x => x.Length, true));
// Assert
Assert.IsNotNull(myStringList);
Assert.AreEqual(5, myStringList.Count);
Assert.AreEqual("abcde", myStringList(0));
Assert.AreEqual("abcd", myStringList(1));
Assert.AreEqual("abc", myStringList(2));
Assert.AreEqual("ab", myStringList(3));
Assert.AreEqual("a", myStringList(4));
}
}