<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2908000077104428568</id><updated>2012-02-15T22:23:07.382-08:00</updated><category term='C#'/><category term='tri'/><category term='csharp'/><category term='fun'/><category term='programmation'/><category term='orienté-objet'/><category term='generics'/><category term='brainfuck'/><category term='présentation'/><category term='.Net'/><category term='tutorial'/><title type='text'>Chloé, qui programme (en Brainfuck)</title><subtitle type='html'>Orienté-Objet, C#, .Net, c'est bien !</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://chloeqp.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://chloeqp.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chloé Desoutter</name><uri>http://www.blogger.com/profile/14153448217146404529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.geekzone.fr/ipb/uploads/photo-11947.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2908000077104428568.post-5315355599324262607</id><published>2007-12-03T09:06:00.000-08:00</published><updated>2007-12-03T10:04:20.803-08:00</updated><title type='text'>Simuler un explorateur web avec C# et .Net</title><content type='html'>&lt;p&gt;Tous les sites ne proposent pas une API pour récupérer leurs contenus. Toutefois, on veut pouvoir récupérer des informations venant d'eux. Pour ce faire, on a besoin de faire des requêtes HTTP et de parser le résultat pour en tirer ce que l'on veut. Notez qu'on ne fera pas d'interprétation JavaScript dans cet article, cela dépasserait largement le cadre de .Net et requerrait des librairies externes.&lt;br /&gt;&lt;br /&gt;Dans cet article, on s'intéressera à la première partie.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Pourquoi est-ce que c'est plus compliqué qu'il n'y paraît ?&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Certains sites peuvent avoir intérêt à modifier les résultats selon qui effectue les requêtes. En effet, on peut imaginer qu'une page Web veuille se présenter de façon optimisée pour le référencement lorsqu'un robot passe sur elle, mais présente une version plus jolie et adaptée à un être humain lorsqu'en effet c'est un être humain (ou du moins un client HTTP de type IE, Safari ou Firefox) qui la visite. On peut aussi imaginer d'autres motifs plus fourbes : par exemple, ne pas transmettre les bons résultats afin d'empêcher l'exploitation de données assistée par ordinateur.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Comment va-t-on faire ?&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;La première chose à faire est de définir l'User-Agent à quelque chose de réaliste. Vous pouvez regarder le vôtre, par exemple, en vérifier &lt;a href="http://facebook.desoutter.org/useragent.php"&gt;cette page&lt;/a&gt; (qui donne entre autres l'information nécessaire dans le champ httpuseragent).&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Faire des requêtes HTTP avec .Net&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;.Net propose des classes spécialisées dans les requêtes web. On peut donc travailler avec sans trop se poser de soucis. La classe qui nous intéresse est la classe HttpWebRequest, qui contient vraiment tout ce qu'on peut vouloir.&lt;br /&gt;Pour l'utiliser, on fait ainsi :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HttpWebRequest maRequete = (HttpWebRequest) HttpWebRequest.Create("http://mon-url.com");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nous devons effectuer un transtypage car la méthode statique Create renvoie un objet WebRequest, plus restreint et moins intéressant.&lt;br /&gt;&lt;br /&gt;Pour lancer la requête et récupérer son résultat, on se sert d'un autre objet, HttpWebResponse. Notez qu'ici .Net a un mécanisme de jeté d'exception en cas de problème qui se passerait (problème de DNS, requête expirée...). On doit donc encadrer le déclenchement de la requête dans une structure try. En général en cas de problème, l'erreur renvoyée sera une WebException.&lt;br /&gt;En reprenant le code ci-dessus, on obtient donc&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HttpWebResponse maReponse;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;  maReponse = (HttpWebResponse) maRequete.GetResponse();&lt;br /&gt;}&lt;br /&gt;catch (WebException) { MessageBox.Show("WebException"); }&lt;br /&gt;catch (Exception e) { MessageBox.Show("Exception non prévue " + e.Message);}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Nous avons maintenant normalement un objet maReponse valant normalement quelque chose de non-nul. Cet objet contient entre autres un Stream qui représente le flux de données envoyé par le serveur HTTP. On le lit comme tout stream. Ici on suppose qu'on va vouloir le lire d'un coup.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;StreamReader lecteur = new StreamReader(maReponse.GetResponseStream());&lt;br /&gt;MessageBox.Show(lecteur.ReadToEnd());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Avec ce code, on affiche le contenu de la page qu'on a demandée.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Et cela suffit ?&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Malheureusement non. Vous connaissez les cookies ? Ce sont de délicieuses délices (excellente recette disponible &lt;a href="http://n0si.free.fr/cookies.rtf"&gt;ici&lt;/a&gt; que je vous recommande) mais surtout des petits morceaux de données que les serveurs web envoient au client pour stocker des informations. Or, par défaut, si on fait nos requêtes successivement, on ne stocke pas les cookies et on recommence de 0 à chaque fois. Les applications web peuvent détecter ce comportement comme caractéristique d'un robot et nous envoyer leurs données "retravaillées", celles que l'on cherche justement à éviter. On doit donc enregistrer les cookies. Et c'est là que .Net est bien fait.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Le principe&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Les cookies sont contenus dans une boiteEnFerBlanc (ou une cookieJar, ou conteneur pour les moins inspirés) que l'on assigne à notre requête à chaque fois. On y stocke aussi les cookies que l'application nous envoie. .Net propose pour stocker les cookies un objet CookieCollection, qui n'est qu'une List&amp;lt;Cookie&amp;gt; un peu déguisée et plus archaïque. Toutefois, on ne peut pas juste assigner cette CookieCollection directement à l'objet maRequete. En effet, un cookie ce n'est pas qu'un nom et une valeur. C'est aussi un domaine. Donc, un exemple&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;CookieCollection boiteEnFerBlanc = new CookieCollection();&lt;br /&gt;boiteEnFerBlanc.Add(new Cookie("Delice1","Au chocolat","/",".mon-domaine.com"));&lt;br /&gt;boiteEnFerBlanc.Add(new Cookie("Delice2","A la vanille","/","web.mon-domaine.com"));&lt;br /&gt;// on doit créer un CookieContainer pour contenir les cookies&lt;br /&gt;maRequete.CookieContainer = new CookieContainer();&lt;br /&gt;// maintenant, on ajoute les cookies qu'on a fabriqués&lt;br /&gt;maRequete.CookieContainer.Add(boiteEnFerBlanc);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Quand on fera le GetResponse(), maRequete enverra les cookies demandés. On doit aussi récupérer les cookies que le site distant va nous envoyer. Pour ce faire, on va réutiliser la boîte en fer blanc.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;  maReponse = (HttpWebResponse) maRequete.GetResponse();&lt;br /&gt;}&lt;br /&gt;catch (WebException) { MessageBox.Show("WebException"); }&lt;br /&gt;catch (Exception e) { MessageBox.Show("Exception non prévue " + e.Message);}&lt;br /&gt;&lt;br /&gt;foreach (Cookie c in maReponse.Cookies)&lt;br /&gt;{&lt;br /&gt; boiteEnFerBlanc.Add(c);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;C'est une approche simpliste mais fonctionnelle. Ensuite, à la prochaine création d'une requête, il suffira de réassigner le champ CookieContainer à boiteEnFerBlanc pour restaurer le contexte. On a maintenant un browser réaliste.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Une petite classe browser&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Parce qu'un post sur ce blog sans la classe qui va avec ce serait dommage, voilà ce qu'on peut envisager de faire comme classe utilitaire. Ca reste de l'ordre du stub, mais ça doit fonctionner ! (reformaté avec Resharper)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.IO;&lt;br /&gt;using System.Net;&lt;br /&gt;&lt;br /&gt;namespace Utilities&lt;br /&gt;{&lt;br /&gt;    public class WebBrowser&lt;br /&gt;    {&lt;br /&gt;        private CookieCollection cookies;&lt;br /&gt;        private string userAgent;&lt;br /&gt;&lt;br /&gt;        public WebBrowser()&lt;br /&gt;        {&lt;br /&gt;            userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11";&lt;br /&gt;            Reset();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public WebBrowser(String userAgent)&lt;br /&gt;        {&lt;br /&gt;            this.userAgent = userAgent;&lt;br /&gt;            Reset();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public string UserAgent&lt;br /&gt;        {&lt;br /&gt;            get { return userAgent; }&lt;br /&gt;            set { userAgent = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Reset()&lt;br /&gt;        {&lt;br /&gt;            cookies = new CookieCollection();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public string Request(String uri)&lt;br /&gt;        {&lt;br /&gt;            HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;&lt;br /&gt;            if (request == null) throw new Exception("Could not create request");&lt;br /&gt;            request.CookieContainer.Add(cookies);&lt;br /&gt;            request.UserAgent = userAgent;&lt;br /&gt;            HttpWebResponse response;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                response = request.GetResponse() as HttpWebResponse;&lt;br /&gt;            }&lt;br /&gt;            catch (WebException e)&lt;br /&gt;            {&lt;br /&gt;                return "[ERROR]WebException " + e.Message;&lt;br /&gt;            }&lt;br /&gt;            catch (Exception e)&lt;br /&gt;            {&lt;br /&gt;                return "[ERROR]General exception " + e.Message;&lt;br /&gt;            }&lt;br /&gt;            if (response == null) throw new Exception("Could not get response");&lt;br /&gt;            foreach (Cookie c in response.Cookies)&lt;br /&gt;            {&lt;br /&gt;                cookies.Add(c);&lt;br /&gt;            }&lt;br /&gt;            return new StreamReader(response.GetResponseStream()).ReadToEnd();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;N'hésitez pas à donner votre feedback.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Un dernier mot&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Pour avoir une approche réellement réaliste, on doit avoir des requêtes assez espacées, d'au moins 5 secondes. Ce temps peut paraître énorme, mais c'est à vous d'étudier selon la nature du site ce qu'on va adopter comme comportement. Je n'ai jamais entendu parler de site qui fasse du tri là-dessus (et la base de données serait très lourde à gérer...) mais autant se faire les plus discrets possibles, c'est le but de la manoeuvre après tout.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2908000077104428568-5315355599324262607?l=chloeqp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chloeqp.blogspot.com/feeds/5315355599324262607/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2908000077104428568&amp;postID=5315355599324262607' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/5315355599324262607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/5315355599324262607'/><link rel='alternate' type='text/html' href='http://chloeqp.blogspot.com/2007/12/simuler-un-explorateur-web-avec-c-et.html' title='Simuler un explorateur web avec C# et .Net'/><author><name>Chloé Desoutter</name><uri>http://www.blogger.com/profile/14153448217146404529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.geekzone.fr/ipb/uploads/photo-11947.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2908000077104428568.post-2929931745331676011</id><published>2007-11-18T08:01:00.000-08:00</published><updated>2007-11-19T10:30:22.341-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='présentation'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='brainfuck'/><title type='text'>Introduction à brainfuck</title><content type='html'>Aujourd'hui, un petit post détente et amusement : on va découvrir le brainfuck.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Brainfuck, c'est quoi ?&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;C'est un &lt;a href="http://en.wikipedia.org/wiki/Turing%20tarpit"&gt;Turing-tarpit&lt;/a&gt;, un langage Turing-complet minimaliste. Son intérêt et de présenter 8 opérateurs ('&amp;lt;','&amp;gt;','+','-','.','.','[',']') et aucune opérande, et de pouvoir implémenter n'importe quel algorithme (pourvu que la taille de la mémoire soit infinie).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Mode de fonctionnement&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;La machine Brainfuck est constituée de 5 élements :&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Un pointeur, ou tête de lecture, qui peut lire et écrire des données, et se déplacer de manière séquentielle &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Une bande de mémoire, qui peut contenir des valeurs entières&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un lecteur de programme, qui ne peut être contrôlé que par lui-même&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un gestionnaire d'entrées (clavier)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un moyen de sortie (écran/imprimante)&lt;h3&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_9esdA55sn5o/R0Ci4fWqYhI/AAAAAAAAAAM/Uo0prcpLLW4/s1600-h/bf01.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_9esdA55sn5o/R0Ci4fWqYhI/AAAAAAAAAAM/Uo0prcpLLW4/s320/bf01.png" alt="" id="BLOGGER_PHOTO_ID_5134282666575290898" border="0" /&gt;&lt;/a&gt;&lt;/h3&gt; &lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Les opérateurs agissent sur la tête de lecture, à l'exception de [ et ] qui agissent sur le lecteur de programme.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;+ incrémente la valeur dans l'élement sous la tête de lecture&lt;/li&gt;&lt;br /&gt;&lt;li&gt;- la décrémente&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt; décale la tête de lecture vers la gauche&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;gt; vers la droite&lt;/li&gt;&lt;br /&gt;&lt;li&gt;, demande l'entrée d'une valeur et la stocke là où la tête de lecture se trouve&lt;/li&gt;&lt;br /&gt;&lt;li&gt;. imprime la valeur contenue sous la tête de lecture&lt;/li&gt;&lt;br /&gt;&lt;li&gt;[ marque le début d'une boucle executée si la valeur sous la tête de lecture est différente de 0.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;] marque la fin de la boucle : quand on le rencontre, on retourne au [ associé (Brainfuck maintient une pile d'associations en interne)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Tout ce qui n'est pas l'un de ces 8 caractères est considéré comme commentaire.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Exemples de programmes&lt;/h3&gt;&lt;br /&gt;Additionner deux valeurs. Ce programme lit deux valeurs, les additionne et affiche le résultat. Il détruit les deux variables d'entrée (i.e. les modifie)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;,&amp;gt;,&amp;lt; on lit les 2 valeurs&lt;br /&gt;[ debut de la boucle&lt;br /&gt;-&amp;gt;+&amp;lt;&lt;br /&gt;]&lt;br /&gt;&amp;gt;. on decale et on affiche&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Faire le perroquet jusqu'à ce que l'on tape sur entrée (ASCII 10)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;, on lit le premier caractère&lt;br /&gt;=D[début de la boucle&lt;br /&gt;|  , on lit le caractère&lt;br /&gt;|  . on l'affiche&lt;br /&gt;|  -----&lt;br /&gt;|  ----- on lui soustrait 10&lt;br /&gt;| ] fin de la boucle, on retourne au début (suivre la fleche)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Idées de programmes pour aller plus loin&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Un programme qui copie une variable dans la case mémoire d'à côté (sans détruire la source)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un programme qui affiche une chaîne de caractère déjà enregistrée (hint : elles se terminent par une valeur nulle)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un programme qui prend une chaîne de caractère en entrée, jusqu'à ce que l'on appuie sur Entrée, puis qui la lit à l'endroit, puis à l'envers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Un multiplicateur, destructeur ou non&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2908000077104428568-2929931745331676011?l=chloeqp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chloeqp.blogspot.com/feeds/2929931745331676011/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2908000077104428568&amp;postID=2929931745331676011' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/2929931745331676011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/2929931745331676011'/><link rel='alternate' type='text/html' href='http://chloeqp.blogspot.com/2007/11/introduction-brainfuck.html' title='Introduction à brainfuck'/><author><name>Chloé Desoutter</name><uri>http://www.blogger.com/profile/14153448217146404529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.geekzone.fr/ipb/uploads/photo-11947.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_9esdA55sn5o/R0Ci4fWqYhI/AAAAAAAAAAM/Uo0prcpLLW4/s72-c/bf01.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2908000077104428568.post-2670341960460464261</id><published>2007-11-17T03:57:00.000-08:00</published><updated>2007-11-17T06:57:00.781-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tri'/><category scheme='http://www.blogger.com/atom/ns#' term='orienté-objet'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Trier et filtrer selon des prédicats</title><content type='html'>La documentation MSDN est pour le moins sybilline sur comment utiliser le tri avec un prédicat (c'est à dire, en précisant le paramètre de tri dans l'argument). C'est un bon premier exemple pour utiliser les &lt;span style="font-weight: bold;"&gt;delegates&lt;/span&gt; (méthodes anonymes).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Premier cas de tri : trier une Liste générique à l'envers&lt;/h3&gt;&lt;br /&gt;Supposons par exemple que l'on veuille trier les élements d'une List&amp;lt;T&amp;gt; à l'envers. Ici, T implémentera IComparable, et aura donc la méthode public int CompareTo(T element), qui renvoie 0 si les deux élements sont égaux, -1 si l'élement element est plus grand que notre instance, et 1 sinon.&lt;br /&gt;&lt;br /&gt;La méthode CompareTo est appelée par défaut. Toutefois, on veut trier à l'envers. La solution sale et à éviter est :&lt;br /&gt;1/ Trier à l'endroit&lt;br /&gt;2/ Inverser la liste&lt;br /&gt;&lt;br /&gt;En effet, on peut faire autrement et de manière beaucoup plus jolie, en utilisant un delegate qui implémente (implicitement) IComparer.&lt;br /&gt;&lt;br /&gt;A supposer que la liste soit nommée maListe, on fera :&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;maListe.Sort(delegate(T el1, T el2) { &lt;br /&gt;return - el1.CompareTo(el2); &lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Deuxième cas de tri : trier des objets selon leurs champs&lt;/h3&gt;&lt;br /&gt;On peut aussi imaginer le cas d'une collection d'objets de classe MaLigne qui comportent chacun trois champs de type String, nommés s1, s2, s3. &lt;br /&gt;Cette collection peut être la représentation logique d'un tableau à 3 colonnes, par exemple. On veut pouvoir trier en ordre ascendant la liste selon s1, s2, ou s3.&lt;br /&gt;Pour ce faire, on va encore utiliser un delegate et le fait que les String soient comparables les unes avec les autres. A supposer que notre collection soit une List&amp;lt;MaLigne&amp;gt; de nom monTableau&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// trier selon s1&lt;br /&gt;monTableau.Sort(delegate(MaLigne el1, &lt;br /&gt;MaLigne el2)&lt;br /&gt;{ &lt;br /&gt;return el1.s1.CompareTo(el2.s1); &lt;br /&gt;});&lt;br /&gt;// trier selon s2&lt;br /&gt;monTableau.Sort(delegate(MaLigne el1, &lt;br /&gt;MaLigne el2)&lt;br /&gt;{ &lt;br /&gt;return el1.s2.CompareTo(el2.s2); &lt;br /&gt;});&lt;br /&gt;// trier selon s3&lt;br /&gt;monTableau.Sort(delegate(MaLigne el1,&lt;br /&gt;MaLigne el2)&lt;br /&gt;{ &lt;br /&gt;return el1.s3.CompareTo(el2.s3); &lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Pour trier dans l'ordre inverse, il suffit de mettre un petit "-" juste après le return. Comme vous pouvez le voir, les facilités de tri sont très importantes en C#.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Filtrer une collection&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;La méthode préférée pour filtrer une collection est d'utiliser FindAll. FindAll prend un prédicat (une condition à vérifier) et retourne une liste chaînée (une List&amp;lt;T&amp;gt;) contenant les élements de la liste qui correspondent à ce prédicat. Le prédicat devra retourner cette fois un booléen selon que l'élement corresponde ou pas.&lt;br /&gt;&lt;br /&gt;Un exemple : supposons que l'on ait une List&amp;lt;CompteEnBanque&amp;gt; comptesEnBanque. Un CompteEnBanque a, entre autres, un champ Solde, de type double (signé).&lt;br /&gt;Pour obtenir la liste des comptes à découvert, on procède ainsi :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;List&amp;lt;CompteEnBanque&amp;gt; aDecouvert = &lt;br /&gt;  comptesEnBanque.FindAll(delegate(CompteEnBanque c)&lt;br /&gt;{ &lt;br /&gt;return c.Solde &lt; 0; &lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Quelques remarques&lt;/h3&gt;&lt;br /&gt;Vous remarquerez que les delegate anonymes n'ont pas de signature. On n'écrit pas int delegate(Foo f, Foo g){}.&lt;br /&gt;On peut aussi trier et filtrer selon des méthodes définies et nommées. Je vous renvoie à la &lt;a href="http://msdn2.microsoft.com/en-us/library/w56d4y5z.aspx"&gt;documentation MSDN&lt;/a&gt; pour des exemples.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2908000077104428568-2670341960460464261?l=chloeqp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chloeqp.blogspot.com/feeds/2670341960460464261/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2908000077104428568&amp;postID=2670341960460464261' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/2670341960460464261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/2670341960460464261'/><link rel='alternate' type='text/html' href='http://chloeqp.blogspot.com/2007/11/trier-et-filtrer-selon-des-prdicats.html' title='Trier et filtrer selon des prédicats'/><author><name>Chloé Desoutter</name><uri>http://www.blogger.com/profile/14153448217146404529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.geekzone.fr/ipb/uploads/photo-11947.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2908000077104428568.post-547435904938635187</id><published>2007-11-17T02:29:00.001-08:00</published><updated>2007-11-17T03:57:18.915-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='orienté-objet'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='generics'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='csharp'/><title type='text'>Generics en C#</title><content type='html'>Il paraît que C# fait un tas de choses merveilleuses au niveau orienté-objet. Entre autres choses, il est capable de travailler avec des &lt;span style="font-weight: bold;"&gt;générics&lt;/span&gt; (le plus souvent des collections d'élements de type inconnu, plus ou moins précisé).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Utiliser les types génériques déjà fournis&lt;/h3&gt;C# propose déjà la plupart des collections génériques dont vous aurez besoin dans des programmes et algorithmes habituels.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;List&amp;lt;T&amp;gt;&lt;/h3&gt;&lt;br /&gt;Ce type fournit une liste chaînée. T est une classe héritant d'Object (donc, n'importe quelle classe). Si T implémente ISortable, alors la List&amp;lt;t&amp;gt;sera triable.&lt;br /&gt;Pour les méthodes, elles sont très explicites. Un exemple :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;List&amp;lt;String&amp;gt; s = new List&amp;ltString&amp;gt;(30);// ce constructeur initialise une liste à la contenance de 30 élements, par défaut&lt;br /&gt;s.Add("toto"); // ajoute la chaîne toto, un objet sans référence autre que dans la liste, à s.&lt;br /&gt;String st = "titi";&lt;br /&gt;s.Add(st); // l'ajout se fait par référence, non pas par copie. Si on altère st, le contenu de la liste sera altéré&lt;br /&gt;s.Add(1,"Ga"); // la chaîne Ga est ajoutée entre toto et titi&lt;br /&gt;Console.WriteLine(s.Contains("Bu")); // affiche false&lt;br /&gt;Console.WriteLine(s.Contains("Ga")); // affiche true&lt;br /&gt;s.ExcessTrim() ;     // libère la mémoire non-utilisée par la liste.&lt;br /&gt;                     // Penser à le faire une fois qu'elle est remplie,&lt;br /&gt;                     // Il vaut mieux allouer en excès puis libérer la mémoire&lt;br /&gt;                     // que devoir réallouer de la mémoire à chaque fois qu'on ajoute un élement&lt;br /&gt;                     // (sauf contraintes particulières, du type systèmes embarqués)&lt;br /&gt;Console.WriteLine(s.Count) ; // affiche 3&lt;br /&gt;s.Clear(); //vide s&lt;br /&gt;Console.WriteLine(s.Count) ; // affiche 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Note : on peut aussi parcourir un dictionnaire avec foreach&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;foreach (T element in maListeGenerique)&lt;br /&gt;{&lt;br /&gt;    element.Squeeze();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Dictionary&amp;lt;T1,T2&amp;gt;&lt;/h3&gt;&lt;br /&gt;Ce type est le type Dictionnaire habituel : à une clé de type T1, on associe une valeur de type T2. Les clés de type T1 ne peuvent être dupliquées (i.e., deux clés ne peuvent être égales). Si on tente d'insérer deux élements avec la même clé, alors on une exception ArgumentException sera levée. A vous de la gérer dans vos programmes. Les méthodes sont encore une fois très explicites, je vous renvoie à la documentation MSDN pour quelques infos. On peut trier un Dictionary selon ses clés ou selon ses valeurs, pourvu que les clés ou les valeurs implément ISortable. Il suffira alors d'appeller monDictionnaire.Keys.Sort() ou monDictionnaire.Values.Sort() pour trier la collection (les joies de l'accès par référence).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Implémenter son propre type générique&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Ici, on va supposer qu'on a besoin d'implémenter une pile (LIFO, donc, le dernier élement entré sera le premier à sortir) générique. Ne me demandez pas quel intérêt il y a à cela, à vous de le trouver ;-)&lt;br /&gt;&lt;br /&gt;Pour ce faire, comme on ne cherche pas forcément la performance, on va simplement utiliser une liste en interne, que l'on va modifier. Notre pile pourra être énumérée, c'est à dire qu'on pourra la parcourir avec un foreach (qui poppera une valeur hors de la liste et la renverra).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace MesExperimentations{&lt;br /&gt;  public class MaStack&amp;lt;T&amp;gt; : IEnumerable&lt;br /&gt;  {&lt;br /&gt;   private List&amp;lt;T&amp;gt; pListeInterne;&lt;br /&gt;   public MaStack()&lt;br /&gt;   {&lt;br /&gt;    pListeInterne = new List&amp;lt;T&amp;gt;();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public MaStack(int capacity)&lt;br /&gt;   {&lt;br /&gt;    pListeInterne = new List&amp;lt;T&amp;gt;(capacity);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public T Pop()&lt;br /&gt;   {&lt;br /&gt;    T element = maListe[maListe.Count-1];&lt;br /&gt;    maListe.RemoveAt(maListe.Count-1); // retire le dernier element de la liste&lt;br /&gt;    return element;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Push(T element)&lt;br /&gt;   {&lt;br /&gt;    maListe.Insert(maListe.Count,element); // insère l'élement au bout de la liste&lt;br /&gt;   }&lt;br /&gt;   // ceci est la méthode à implémenter pour IEnumerable&lt;br /&gt;   public IEnumerator&amp;lt;T&amp;gt; GetEnumerator()&lt;br /&gt;   {&lt;br /&gt;    int taille = maListe.Count;&lt;br /&gt;    while (taille&gt;=0)&lt;br /&gt;    {&lt;br /&gt;         taille --;&lt;br /&gt;         yield return maListe[taille];&lt;br /&gt;         // un raccourci de C# pour éviter une syntaxe plus lourde&lt;br /&gt;         // le mot yield est un mot magique pour l'énumération.&lt;br /&gt;         // il permet de faire des "return multiples" en un seul bloc de code,&lt;br /&gt;         // sans devoir maintenir de variable globale&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Spécifier des contraintes sur T&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Dans certains cas, faire une collection 100% générique n'est pas une bonne idée. Par exemple, on peut imaginer une liste qui se trie automatiquement à l'insertion. Donc, son type T devra implémenter ISortable. Je ne vais pas l'implémenter ici, je vous laisse le faire.&lt;br /&gt;&lt;br /&gt;La première ligne de la classe sera :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class ListeTriee&amp;lt;T&amp;gt; : List&amp;lt;T&amp;gt; where T: ISortable&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ici, la classe ListeTriee étend la classe List mais impose que le type T implémente l'interface ISortable (celle qui permet de trier).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Un dernier mot&lt;/h3&gt;&lt;br /&gt;Pour aller plus loin et plus en profondeur, comme toujours, rendez-vous sur &lt;a href="http://msdn2.microsoft.com/en-us/library/default.aspx"&gt;MSDN library&lt;/a&gt; et faites des recherches sur Generics.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2908000077104428568-547435904938635187?l=chloeqp.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://chloeqp.blogspot.com/feeds/547435904938635187/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2908000077104428568&amp;postID=547435904938635187' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/547435904938635187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2908000077104428568/posts/default/547435904938635187'/><link rel='alternate' type='text/html' href='http://chloeqp.blogspot.com/2007/11/generics-en-c.html' title='Generics en C#'/><author><name>Chloé Desoutter</name><uri>http://www.blogger.com/profile/14153448217146404529</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.geekzone.fr/ipb/uploads/photo-11947.jpg'/></author><thr:total>0</thr:total></entry></feed>
