Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

ICOMPARER GÉNÉRIQUE ET RÉFLEXION


Information sur la source

Description

Cliquez pour voir la capture en taille normale
Cette source pourrais très bien être implémenter un Winform.
Petit exemple illustrant la comparaison de n'importe quel objet par rapport à un nom d'une de ses méthodes/propriété/retour de méthode.
La classe IComparer est utilisée, ainsi on peut l'utiliser pour tout objet qui utilise la méthode Sort(IComparer), les liste par exemple.
L'implémentation est assez simple c'est se qui fait la force de ce comparateur.
 

Source

  • //On cree notre petite liste
  • ListeEntreprise = new List<FirmUser>();
  • ListeEntreprise.Add(new FirmUser("Bouygues Télécom"));
  • ListeEntreprise.Add(new FirmUser("France Télécom"));
  • ListeEntreprise.Add(new FirmUser("SFR"));
  • ListeClient = new List<ClientUser>();
  • ListeClient.Add(new ClientUser("Martin", "Jean", 20, "20 rue du louvre",ListeEntreprise[1]));
  • ListeClient.Add(new ClientUser("Zert", "Romain", 25, "20 allé du louvre",ListeEntreprise[2]));
  • ListeClient.Add(new ClientUser("Armand", "Bob", 50, "Place du louvre",ListeEntreprise[0]));
  • ListeClient.Add(new ClientUser("Martin", "Julie", 18, "258 rue du louvre",ListeEntreprise[1]));
  • ListeClient.Add(new ClientUser("Hounou", "koffi", 34, "20 rue du louvre",ListeEntreprise[0]));
  • //On cree le filtre
  • private List<ObjectComparerFilter> _Filter;
  • public List<ObjectComparerFilter> Filter
  • {
  • get
  • {
  • if (_Filter == null)
  • {
  • _Filter = new List<ObjectComparerFilter>();
  • if (string.IsNullOrEmpty(HiddenFilter.Value))
  • {
  • HiddenFilter.Value = "nom,0;prenom,0;age,0;adresse,0;entreprise,0";
  • }
  • string[] filterTmp = HiddenFilter.Value.Split(';');
  • foreach (string str in filterTmp)
  • {
  • string[] strTmp = str.Split(',');
  • _Filter.Add(new ObjectComparerFilter(strTmp[0], ((ObjectComparerFilter.Order)(int.Parse(strTmp[1])))));
  • }
  • }
  • return _Filter;
  • }
  • set
  • {
  • _Filter = value;
  • HiddenFilter.Value = "";
  • for (int i = 0; i < value.Count; i++)
  • {
  • HiddenFilter.Value += value[i].nom + "," + ((int)value[i].order).ToString();
  • if (i < value.Count - 1)
  • {
  • HiddenFilter.Value += ";";
  • }
  • }
  • }
  • }
  • //Et on trie
  • //le filtre par défaut: "nom,0;prenom,0;age,0;adresse,0;entreprise,0";
  • //nom== nom de la proriété, 0 = pas de trie (-1 et 1 sinon)
  • ObjectComparer<ClientUser> _ObjectComparer = new ObjectComparer<ClientUser>(Filter);
  • ListeClient.Sort(_ObjectComparer);
//On cree notre petite liste
 ListeEntreprise = new List<FirmUser>();
 ListeEntreprise.Add(new FirmUser("Bouygues Télécom"));
 ListeEntreprise.Add(new FirmUser("France Télécom"));
 ListeEntreprise.Add(new FirmUser("SFR"));
 ListeClient = new List<ClientUser>();
 ListeClient.Add(new ClientUser("Martin", "Jean", 20, "20 rue du louvre",ListeEntreprise[1]));
 ListeClient.Add(new ClientUser("Zert", "Romain", 25, "20 allé du louvre",ListeEntreprise[2]));
 ListeClient.Add(new ClientUser("Armand", "Bob", 50, "Place du louvre",ListeEntreprise[0]));
 ListeClient.Add(new ClientUser("Martin", "Julie", 18, "258 rue du louvre",ListeEntreprise[1]));
 ListeClient.Add(new ClientUser("Hounou", "koffi", 34, "20 rue du louvre",ListeEntreprise[0]));
 
//On cree le filtre 
private List<ObjectComparerFilter> _Filter;
public List<ObjectComparerFilter> Filter
{
	get
	{
		if (_Filter == null)
		{
			_Filter = new List<ObjectComparerFilter>();
			if (string.IsNullOrEmpty(HiddenFilter.Value))
			{
				HiddenFilter.Value = "nom,0;prenom,0;age,0;adresse,0;entreprise,0";
			}
			string[] filterTmp = HiddenFilter.Value.Split(';');
			foreach (string str in filterTmp)
			{
				string[] strTmp = str.Split(',');
				_Filter.Add(new ObjectComparerFilter(strTmp[0], ((ObjectComparerFilter.Order)(int.Parse(strTmp[1])))));
			}
		}
		return _Filter;
	}
	set
	{
		_Filter = value;
		HiddenFilter.Value = "";
		for (int i = 0; i < value.Count; i++)
		{
			HiddenFilter.Value += value[i].nom + "," + ((int)value[i].order).ToString();
			if (i < value.Count - 1)
			{
				HiddenFilter.Value += ";";
			}
		}
	}
}

//Et on trie
//le filtre par défaut: "nom,0;prenom,0;age,0;adresse,0;entreprise,0";
//nom== nom de la proriété, 0 = pas de trie (-1 et 1 sinon)
ObjectComparer<ClientUser> _ObjectComparer = new ObjectComparer<ClientUser>(Filter);
ListeClient.Sort(_ObjectComparer);

 


Conclusion

Le reste dans le zip :)

 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Commentaires et avis

signaler à un administrateur
Commentaire de lakichemole le 14/04/2008 15:55:40

Voilà ma première source j'attends les retours :)

signaler à un administrateur
Commentaire de jesusonline le 14/04/2008 17:22:14 administrateur CS

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.

signaler à un administrateur
Commentaire de lakichemole le 14/04/2008 17:37:33

- 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 :).

signaler à un administrateur
Commentaire de jesusonline le 14/04/2008 18:39:46 administrateur CS

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<Person>

signaler à un administrateur
Commentaire de lakichemole le 14/04/2008 19:22:19

Ok en gros si j'ai bien compris pour un objet complexe ça donnerais ça:
List<User> 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<User> 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é.

signaler à un administrateur
Commentaire de lakichemole le 14/04/2008 19:46:49

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!

signaler à un administrateur
Commentaire de jesusonline le 14/04/2008 20:58:20 administrateur CS

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<U>(T item) where U : IComparable<U>;

    public static void Sort<U>(List<T> l, params Get<U>[] m) where U : IComparable<U>
    {
        l.Sort(delegate(T item1, T item2)
        {
            int v = 1;
            foreach (Get<U> 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 !

signaler à un administrateur
Commentaire de lakichemole le 15/04/2008 09:27:02

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 :/

signaler à un administrateur
Commentaire de jesusonline le 15/04/2008 10:09:04 administrateur CS

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.

signaler à un administrateur
Commentaire de lakichemole le 15/04/2008 10:56:00

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?

signaler à un administrateur
Commentaire de jesusonline le 15/04/2008 11:08:58 administrateur CS

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;

signaler à un administrateur
Commentaire de lakichemole le 15/04/2008 11:24:21

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<User> liste ou User à la propriété age ça donne quoi avec ta méthode statique?
orderer<User>.Sort<String>(Liste,... (la suite?)

signaler à un administrateur
Commentaire de jesusonline le 15/04/2008 11:48:58 administrateur CS

pas besoin de T y'aura de l'inference de type :

Orderer.Sort<IComparable>(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<U>[] 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.

Ajouter un commentaire



Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,265 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.