ICOMPARER GÉNÉRIQUE ET RÉFLEXION

lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009 - 14 avril 2008 à 15:55
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 - 15 avril 2008 à 11:48
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/46356-icomparer-generique-et-reflexion

jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
15 avril 2008 à 11:48
pas besoin de T y'aura de l'inference de type :

Orderer.Sort(l, delegate(Person p){
return p.Name;
}, delegate(Person p){
return p.Age;
});

En fait après reflexion, je pense que tu pourrais remplacer U par IComparable dans la méthode Sort (et supprimer la contrainte where) car tu peux pas avoir une Get[] où U aurait un type différent, donc autant passer par un IComparable directement.

le mot clé params veut dire que tu peux mettre autant d'argument que voulu, ils vont se regrouper dans un tableau automatiquement.
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
15 avril 2008 à 11:24
Ok j'ai donc pas tout compris,Je vais abuser de ta patience encore une fois mais en gros l'appel de ta fonction pour une List liste ou User à la propriété age ça donne quoi avec ta méthode statique?
orderer.Sort<String>(Liste,... (la suite?)
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
15 avril 2008 à 11:08
On trie d'abord par la premiere propriété puis la seconde propriété. Si les premières propriétés sont égales alors on check la seconde et ainsi de suite donc il est nécessaire de faire le break;
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
15 avril 2008 à 10:56
oki c'est qu'une question d'assemblie alors? Y a pas une question d'OS aussi?
Sinon je viens de faire quelque petit tests pour confirmer par des fait se que tu disait à propos des perfs:
avec ta méthode pour 2400 lignes : 15 ms pour trier par nom
avec ma méthode pour 2400 lignes : 190 ms pour trier par nom
et la tu me diras "jte l'avais dis" et là je répondrais:
"Tu est peut être le jésus du .NET mais j'en suis le St thomas je ne crois que se que je vois!"
:)
Bon si j'ai bien compris je remplace mon objet par ta méthode static Orderer par contre encore un truc pourquoi tu fais ça dans ton foreach:
if (v != 0)
break;
Ca voudrais dire qu'on ne peut trier que sur une colone ou que l'ordre de trie est forcément l'ordre des paramètres?
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
15 avril 2008 à 10:09
oui et non, le marketing chez microsoft c'est du n'importe quoi :)

le compilateur C#3 compile pour la CLR2 donc tu peux utiliser les assemblies du framework 2.0.
Le compilateur C#3 est livré avec .net 3.5 donc aussi avec VS2008, c'est pour ca que VS2008 permet de "compiler" pour .net 2.0, en fait il ne fait que ne pas inclure les assemblies du framework 3.x.

Le framework 3.0 et 3.5 tourne sur la CLR2 également.
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
15 avril 2008 à 09:27
Oki je suis plus convaincu déjà :) j'y vois plus claire :) C#3 ça veut bien dire framework 3.0 au moins? si c'est le cas je suis contraint au 2.0 pour l'instant :/
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
14 avril 2008 à 20:58
Arf je suis bête pour le chainage ca va être plus compliqué :) faut le faire dans le delegate ou alors utilisé linq donc C#3

l.Sort(delegate(p1, p2){
int v = p1.Name.compareTo(p2.Age);
if (v == 0)
v = p1.Age.compareTo(p3.Age);
return v;
});

niveau vitesse ce code sera BEAUCOUP plus rapide que ce que tu as fait, la Reflection est extremement couteuse.

Toutes les simplifications de syntaxe que je vois pour ce simple bout de code viennent avec C#3. Tu peux éventuellement avoir un classe static du genre

public static class orderer<T>
{

public delegate U Get(T item) where U : IComparable;

public static void Sort(List<T> l, params Get[] m) where U : IComparable
{
l.Sort(delegate(T item1, T item2)
{
int v = 1;
foreach (Get g in m)
{
v = g(item1).CompareTo(g(item2));
if (v != 0)
break;
}
return v;
});
}
}

Puis utiliser ca ainsi

Sort(l, delegate(Person p){
return p.Name;
}, delegate(Person p){
return p.Age;
});

Avec les lambda expression en C#3
Sort(l, p => p.Name, p => p.Age);

Sauf erreur de ma part, le petit bout de code est équivalent à tout ton code pour trier une liste mis à part qu'il y a aura une vérification à la compil.

L'autre solution est d'utiliser un DataTable/Dataview qui fait déjà tous ce code pour toi !
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
14 avril 2008 à 19:46
Je viens de tester par contre je vois pas comment chainer une List<T>.Sort renvoyant void et non une liste et si on refais un Sort apres ça annule celui d'avant.
Donc la méthode serait de faire ça dans le la méthode delegate.
Cela m'amène à une autre question d'ailleurs, y a-t-il une option au sort ou une technique simple pour dire qu'on veut faire un DESCENDING et non un ASCENDING? (à part en multipliant le résultat du CompareTo par -1)
Bon je sais que je comprends pas tout tout de suite merci de votre patience!
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
14 avril 2008 à 19:22
Ok en gros si j'ai bien compris pour un objet complexe ça donnerais ça:
List l;
//...on la remplie...
l.Sort(delegate(User u1, User u2){
return u1.name.CompareTo(u2.name);
}).Sort(delegate(User u1, User u2){
return u1.age.CompareTo(u2.age);
});
Pour un trie sur 2 colonnes, ça fait un peu usine a gaz non?
Car mon but réel était de faire un objet facilement réutilisable et moi ce code je le remplace par ça:
List l;
//...on la remplie...
ObjectComparer objComp= new ObjectComparer("nom","age");
l.Sort(objComp);

L'inconvénient étant que si l'utilisateur se plante dans le nom des colonne on ne le détectera pas à la compilation mais lors de l'éxécution.
Après niveau perf faudrait voir j'ai pas testé.
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
14 avril 2008 à 18:39
La méthode Sort prend un Comparison<T> qui est un delegate qui a cette signature
delegate int SortComparison<T>(T item1, T item2)

tu peux donc faire

l.Sort(new Comparison<String>(delegate(String s1, String s2){
return s1.CompareTo(s2);
}));

C# 2 permet de simplifier un petit peu :
l.Sort(delegate(String s1, String s2){
return s1.CompareTo(s2);
});

C#3 permet de simplifier encore plus via les lambda expression
l.Sort((s1, s2) => s1.CompareTo(s2));

Tu peux bien sur chainé cet exmple pour avoir un tri sur plusieurs champs

en linq (C#3) ca donne

var q = from p in l
orderby p.Name, p.Age
select p;

q et l étant une List
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
14 avril 2008 à 17:37
- Pour le gridview: Oui c'est vrai mais là mon but était surtout de montrer le comparer donc j'ai fait avec mes premiers reflexes pour la présentation
- en se qui concerne le myList.Sort((p1, p2))je vais voir se qu'il fait avec ta méthode :) mais il est tout a fait possible que j'ai réinventé la roue :).
jesusonline Messages postés 6814 Date d'inscription dimanche 15 décembre 2002 Statut Membre Dernière intervention 13 octobre 2010 29
14 avril 2008 à 17:22
Après un rapide coup d'oeil. Voici mes remarques :

- Pourquoi ne pas avoir utilisé un Gridview ? C'est son rôle d'afficher une grille de données.
- Je comprend pas pourquoi tu t'es embeté avec de la reflection. La méthode Sort de List<T> prend un delegate qui permet de faire le tri facilement.
myList.Sort((p1, p2) => p1.Name.CompareTo(p2.Name))
et si tu veux chainé.
myList.Sort((p1, p2) => p1.Name.CompareTo(p2.Name)).Sort((p1, p2) => p1.Age.CompareTo(p2.Age));
tu peux aussi utilisé une requête linq ce qui fais encore moins de ligne :)

Ton code est interessant (j'ai pas tout lu) mais tu n'utilises pas .net de la meilleure façon.
lakichemole Messages postés 253 Date d'inscription vendredi 13 juin 2003 Statut Membre Dernière intervention 18 mai 2009
14 avril 2008 à 15:55
Voilà ma première source j'attends les retours :)
Rejoignez-nous