Si necesita ordenar listas (no ILists) de diferentes clases sin la necesidad de crear una clase comparer separada para todas ellas y aún mantener sus clases de entidad limpias (no desea implementar IComparable), puede utilice la siguiente (compatible con .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.");
}
}
también debes cumplir los delegados Func si está utilizando .NET 2.0 (que se encuentra en Replacing Func with delegates C#):
public delegate TResult Func<T, TResult>(T t);
public delegate TResult Func<T, U, TResult>(T t, U u);
uso:
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty) // Ascending
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty, true) // Descending
Algunos sencilla prueba de la unidad:
[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));
}
}
para que no solo tire la IList a un IList. ¿Por qué es un lanzamiento seguro? –
No copie la publicación completa. Parecería que es lo correcto para asegurarse de que se preserve el contenido, pero la copia de toda la publicación probablemente requiera un permiso explícito del titular de los derechos de autor. Sin embargo, puedes y debes crear un resumen. –
@EddieDeyo: Sé que esto tiene algunos años, pero es porque IList realmente no existe, sino que es un IList de LanguageDto, que por supuesto es un IList de LanguageDto. T es (principalmente) una ilusión de tiempo de compilación. La "diferencia" entre un IList e IList es que para IList Item [0] devuelve un Object, pero para IList Item [0] devuelve un Object que siempre será una T, y si T es una struct/primitive the Object no habrá sido encuadrado Entonces, un elenco de IList a IList sería seguro (innecesario, pero seguro) pero el reverso no es –
jmoreno