Si vous avez besoin de trier les listes (pas ILists) de classes différentes sans avoir besoin de créer une classe de tri séparée pour chacune d'entre elles tout en gardant vos classes d'entités propres (vous ne voulez pas implémenter IComparable), vous pouvez utiliser les éléments suivants (compatible avec .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.");
}
}
vous aurez également besoin des délégués Func si vous utilisez .NET 2.0 (disponible sur Replacing Func with delegates C#):
public delegate TResult Func<T, TResult>(T t);
public delegate TResult Func<T, U, TResult>(T t, U u);
utilisation:
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty) // Ascending
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty, true) // Descending
Certains tests simples de l'unité:
[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));
}
}
Alors il ne redore juste le IList à un IList. Pourquoi est-ce un casting sûr à faire? –
Ne pas copier tout le message. Il semble que la bonne chose à faire pour s'assurer que le contenu est préservé, mais la copie de l'ensemble du poste nécessite probablement une autorisation explicite du détenteur des droits d'auteur. Vous pouvez et devriez créer un résumé, cependant. –
@EddieDeyo: Je sais que c'est vieux de quelques années, mais c'est parce que IList n'existe pas vraiment, mais c'est un IList de LanguageDto, qui est bien sûr un IList de LanguageDto. T est (principalement) une illusion de temps de compilation. La "différence" entre un IList et IList est que pour IList Item [0] retourne un Object, mais pour IList Item [0] retourne un Object qui sera toujours un T, et si T est un struct/primitive l'Object n'aura pas été emballé. Ainsi, une distribution de IList à IList serait sûre (inutile, mais sûre) mais l'inverse n'est pas –
jmoreno