Anda di halaman 1dari 382

Apprenez dvelopper en C#

Par nico.pyright

www.siteduzero.com

Licence Creative Commons BY-NC-SA 2.0 Dernire mise jour le 24/04/2012

Sommaire

1/381

Sommaire
Sommaire ........................................................................................................................................... 1 Lire aussi ............................................................................................................................................ 2 Apprenez dvelopper en C# ............................................................................................................ 4 Partie 1 : Les rudiments du langage C# .............................................................................................. 5
Introduction au C# ............................................................................................................................................................. 6
Avant propos ............................................................................................................................................................................................................... 6 A qui sadresse ce tutoriel ? ........................................................................................................................................................................................ 6 Esprit du tutoriel .......................................................................................................................................................................................................... 6 Dure dapprentissage ................................................................................................................................................................................................ 6 C'est tout ? .................................................................................................................................................................................................................. 6 Allez plus loin ! ............................................................................................................................................................................................................ 6 Qu'est-ce que le C# ? .................................................................................................................................................................................................. 7 Comment sont cres les applications informatiques ? .............................................................................................................................................. 7 Une application informatique : qu'est-ce que c'est ? ................................................................................................................................................... 7 Comment crer des programmes "simplement" ? ...................................................................................................................................................... 7 Excutables ou assemblages ? ................................................................................................................................................................................ 10 Qu'est-ce que le framework .NET ? .......................................................................................................................................................................... 10

Crer un projet avec Visual C# 2010 express ................................................................................................................ 12


Que faut-il pour dmarrer ? ....................................................................................................................................................................................... Installer Visual C# 2010 express ............................................................................................................................................................................... Dmarrer Visual C# 2010 Express ............................................................................................................................................................................ Crer un projet .......................................................................................................................................................................................................... Analyse rapide de lenvironnement de dveloppement et du code gnr .............................................................................................................. Ecrire du texte dans notre application ....................................................................................................................................................................... L'excution du projet ................................................................................................................................................................................................. Ecrire une ligne de code ........................................................................................................................................................................................... Le caractre de terminaison de ligne ........................................................................................................................................................................ Les commentaires ..................................................................................................................................................................................................... La compltion automatique ....................................................................................................................................................................................... Quest-ce quune variable ? ...................................................................................................................................................................................... Les diffrents types de variables ............................................................................................................................................................................... Affectations, oprations, concatnation .................................................................................................................................................................... Les caractres spciaux dans les chaines de caractres ......................................................................................................................................... 13 13 17 17 19 21 21 26 28 29 30 32 34 35 37

La syntaxe gnrale du C# ............................................................................................................................................. 26

Les variables ................................................................................................................................................................... 32

Les instructions conditionnelles ...................................................................................................................................... 41


Les oprateurs de comparaison ................................................................................................................................................................................ 42 L'instruction "if" .......................................................................................................................................................................................................... 42 L'instruction "Switch" ................................................................................................................................................................................................. 45

Les blocs de code et la porte dune variable ................................................................................................................. 47


Les blocs de code ..................................................................................................................................................................................................... 48 La porte dune variable ............................................................................................................................................................................................ 48

Les mthodes .................................................................................................................................................................. 50


Crer une mthode ................................................................................................................................................................................................... La mthode spciale Main() ...................................................................................................................................................................................... Paramtres dune mthode ....................................................................................................................................................................................... Retour dune mthode ............................................................................................................................................................................................... Les tableaux .............................................................................................................................................................................................................. Les listes ................................................................................................................................................................................................................... Liste ou tableau ? ...................................................................................................................................................................................................... Les numrations ...................................................................................................................................................................................................... Linstruction using ...................................................................................................................................................................................................... La bibliothque de classes .NET ............................................................................................................................................................................... Rfrencer une assembly ......................................................................................................................................................................................... Dautres exemples .................................................................................................................................................................................................... 50 51 52 54 58 60 63 63 66 68 69 73

Tableaux, listes et numrations ..................................................................................................................................... 57

Utiliser le framework .NET ............................................................................................................................................... 65

TP : Bonjour c'est le week-end ... .................................................................................................................................... 75


Instructions pour raliser le TP .................................................................................................................................................................................. 76 Correction .................................................................................................................................................................................................................. 76 Aller plus loin ............................................................................................................................................................................................................. 78

Les boucles ..................................................................................................................................................................... 80


La boucle For ............................................................................................................................................................................................................ 80 La boucle Foreach ..................................................................................................................................................................................................... 84 La boucle While ......................................................................................................................................................................................................... 88 Les instructions break et continue ............................................................................................................................................................................. 89

TP : Calculs en boucle .................................................................................................................................................... 92


Instructions pour raliser le TP .................................................................................................................................................................................. 92 Correction .................................................................................................................................................................................................................. 93 Aller plus loin ............................................................................................................................................................................................................. 94

Partie 2 : Un peu plus loin avec le C# ............................................................................................... 96


Les conversions entre les types ...................................................................................................................................... 97

www.siteduzero.com

Lire aussi

2/381

Entre les types compatibles : Le casting ................................................................................................................................................................... 97 Entre les types incompatibles ................................................................................................................................................................................. 101

Lire le clavier dans la console ....................................................................................................................................... 103


Lire une phrase ....................................................................................................................................................................................................... 104 Lire un caractre ..................................................................................................................................................................................................... 105

Utiliser le dbogueur ..................................................................................................................................................... 107


A quoi a sert ? ........................................................................................................................................................................................................ 108 Mettre un point darrt et avancer pas pas ........................................................................................................................................................... 108 Observer des variables ............................................................................................................................................................................................ 110 Revenir en arrire .................................................................................................................................................................................................... 112 La pile des appels .................................................................................................................................................................................................... 113

TP : le jeu du plus ou du moins ..................................................................................................................................... 115


Instructions pour raliser le TP ................................................................................................................................................................................ 115 Correction ................................................................................................................................................................................................................ 115 Aller plus loin ........................................................................................................................................................................................................... 116

La ligne de commande .................................................................................................................................................. 118


Quest-ce que la ligne de commande ? ................................................................................................................................................................... 118 Passer des paramtres en ligne de commande ...................................................................................................................................................... 118 Lire la ligne de commande ...................................................................................................................................................................................... 120

TP : Calculs en ligne de commande ............................................................................................................................. 122


Instructions pour raliser le TP ................................................................................................................................................................................ 123 Correction ................................................................................................................................................................................................................ 123 Aller plus loin ........................................................................................................................................................................................................... 125

Partie 3 : Le C#, un langage orient objet ....................................................................................... 127


Introduction la programmation oriente objet ............................................................................................................ 128
Qu'est-ce qu'un objet ? ............................................................................................................................................................................................ 128 Lencapsulation ....................................................................................................................................................................................................... 129 Hritage ................................................................................................................................................................................................................... 129 Polymorphisme - Substitution ................................................................................................................................................................................. 130 Interfaces ................................................................................................................................................................................................................. 131 quoi sert la programmation oriente objet ? ........................................................................................................................................................ 131

Crer son premier objet ................................................................................................................................................ 133


Tous les types C# sont des objets ........................................................................................................................................................................... 133 Les classes ............................................................................................................................................................................................................. 133 Les mthodes .......................................................................................................................................................................................................... 135 Notion de visibilit ................................................................................................................................................................................................... 139 Les proprits .......................................................................................................................................................................................................... 141 Les variables membres : ......................................................................................................................................................................................... 141 Les proprits : ........................................................................................................................................................................................................ 142 Les proprits auto-implmentes : ........................................................................................................................................................................ 145

Manipuler des objets ..................................................................................................................................................... 148


Le constructeur ........................................................................................................................................................................................................ 149 Instancier un objet ................................................................................................................................................................................................... 151 Le mot-cl this ......................................................................................................................................................................................................... 154

La POO et le C# ............................................................................................................................................................ 155


Des types, des objets, type valeur et type rfrence .............................................................................................................................................. Hritage ................................................................................................................................................................................................................... Substitution ............................................................................................................................................................................................................. Polymorphisme ....................................................................................................................................................................................................... La conversion entre les objets avec le casting ........................................................................................................................................................ Comparer des objets ............................................................................................................................................................................................... Les interfaces .......................................................................................................................................................................................................... Les classes et les mthodes abstraites .................................................................................................................................................................. Les classes partielles .............................................................................................................................................................................................. Classes statiques et mthodes statiques ................................................................................................................................................................ Les classes internes ................................................................................................................................................................................................ Les types anonymes et le mot cl var ..................................................................................................................................................................... Instructions pour raliser le TP ................................................................................................................................................................................ Correction ................................................................................................................................................................................................................ Aller plus loin ........................................................................................................................................................................................................... Deuxime partie du TP ............................................................................................................................................................................................ Correction ................................................................................................................................................................................................................ Passage de paramtres par valeur ......................................................................................................................................................................... Passage de paramtres en mise jour .................................................................................................................................................................. Passage des objets par rfrence .......................................................................................................................................................................... Passage de paramtres en sortie ........................................................................................................................................................................... Une structure est presque une classe ..................................................................................................................................................................... quoi sert une structure ? ...................................................................................................................................................................................... Crer une structure ................................................................................................................................................................................................. Passage de structures en paramtres .................................................................................................................................................................... Dautres structures ? ............................................................................................................................................................................................... Qu'est-ce que les gnriques ? ............................................................................................................................................................................... Les types gnriques du framework .NET .............................................................................................................................................................. Crer une mthode gnrique ................................................................................................................................................................................ Crer une classe gnrique .................................................................................................................................................................................... 156 158 171 176 179 186 189 196 200 201 207 208 212 213 219 221 221 227 228 229 231 233 233 233 236 237 239 239 240 243

Notions avances de POO en C# ................................................................................................................................. 185

TP Programmation Oriente Objet ................................................................................................................................ 211

Mode de passage des paramtres une mthode ...................................................................................................... 226

Les structures ................................................................................................................................................................ 232

Les gnriques .............................................................................................................................................................. 238

www.siteduzero.com

Lire aussi

3/381
245 245 246 250 252 253 257 258 260 263

La valeur par dfaut dun type gnrique ................................................................................................................................................................ Les interfaces gnriques ....................................................................................................................................................................................... Les restrictions sur les types gnriques ................................................................................................................................................................ Les types nullables .................................................................................................................................................................................................. Instructions pour raliser la premire partie du TP ................................................................................................................................................. Correction ................................................................................................................................................................................................................ Instructions pour raliser la deuxime partie du TP ................................................................................................................................................ Correction ................................................................................................................................................................................................................ Aller plus loin ........................................................................................................................................................................................................... Implmenter une interface explicitement ................................................................................................................................................................

TP types gnriques ..................................................................................................................................................... 252

Les mthodes d'extension ............................................................................................................................................. 265


Qu'est-ce qu'une mthode d'extension ................................................................................................................................................................... 266 Crer une mthode d'extension .............................................................................................................................................................................. 266 Utiliser une mthode d'extension ............................................................................................................................................................................ 267

Dlgus, vnements et expressions lambdas .......................................................................................................... 270


Les dlgus (delegate) .......................................................................................................................................................................................... Diffusion multiple, le Multicast ................................................................................................................................................................................. Les dlgus gnriques Action et Func ................................................................................................................................................................ Les expressions lambdas ........................................................................................................................................................................................ Les vnements ...................................................................................................................................................................................................... 270 273 274 276 277

Grer les erreurs : les exceptions ................................................................................................................................. 282


Intercepter une exception ........................................................................................................................................................................................ 282 Intercepter plusieurs exceptions ............................................................................................................................................................................. 286 Le mot-cl finally ..................................................................................................................................................................................................... 288 Lever une exception ................................................................................................................................................................................................ 290 Propagation de lexception ...................................................................................................................................................................................... 291 Crer une exception personnalise ......................................................................................................................................................................... 293

TP vnements et mto .............................................................................................................................................. 296


Instructions pour raliser le TP ................................................................................................................................................................................ 296 Correction ................................................................................................................................................................................................................ 296 Aller plus loin ........................................................................................................................................................................................................... 299

Partie 4 : C# avanc ....................................................................................................................... 302


Crer un projet bibliothques de classes ...................................................................................................................... 302
Pourquoi crer une bibliothque de classes ? ........................................................................................................................................................ Crer un projet de bibliothque de classe ............................................................................................................................................................... Proprits de la bibliothque de classe .................................................................................................................................................................. Gnrer et utiliser une bibliothque de classe ........................................................................................................................................................ Le mot-cl internal ................................................................................................................................................................................................... Empcher une classe de pouvoir tre hrite ......................................................................................................................................................... Prcisions sur les types et gestion mmoire ........................................................................................................................................................... Masquer une mthode ............................................................................................................................................................................................ Le mot-cl yield ....................................................................................................................................................................................................... Le formatage de chaines, de dates et la culture ..................................................................................................................................................... Les attributs ............................................................................................................................................................................................................. La rflexion .............................................................................................................................................................................................................. 302 303 305 306 308 311 312 315 318 322 330 332

Plus loin avec le C# et .NET .......................................................................................................................................... 311

La configuration d'une application ................................................................................................................................. 335


Rappel sur les fichiers XML ..................................................................................................................................................................................... 336 Crer le fichier de configuration .............................................................................................................................................................................. 337 Lecture simple dans la section de configuration prdfinie : AppSettings .............................................................................................................. 338 Lecture des chaines de connexion la base de donnes ...................................................................................................................................... 341 Crer sa propre section de configuration partir dun type prdfini ...................................................................................................................... 341 Les groupes de sections ......................................................................................................................................................................................... 344 Crer une section de configuration personnalise .................................................................................................................................................. 345 Crer une section personnalise avec une collection ............................................................................................................................................. 347

Introduction LINQ ....................................................................................................................................................... 351


Les requtes Linq .................................................................................................................................................................................................... 352 Les mthodes dextensions Linq ............................................................................................................................................................................. 359 Excution diffre .................................................................................................................................................................................................... 362 Rcapitulatif des oprateurs de requtes ............................................................................................................................................................... 364

Les tests unitaires ......................................................................................................................................................... 365


Quest-ce quun test unitaire et pourquoi en faire ? ................................................................................................................................................ 366 Notre premier test .................................................................................................................................................................................................... 366 Le framework de test ............................................................................................................................................................................................... 370 Le framework de simulacre ..................................................................................................................................................................................... 378

www.siteduzero.com

Apprenez dvelopper en C#

4/381

Apprenez dvelopper en C#
Par nico.pyright Mise jour : 02/02/2012 Difficult : Facile 23 619 visites depuis 7 jours, class 14/781

Vous avez entendu parler du langage C, du C++, et voil qu'on vous prsente maintenant le C# ! Encore un langage me direz-vous ? Oui, mais pas n'importe lequel !
Il existe beaucoup de langages de programmation, comme le C, le C++, Python, Java... Chacun a ses avantages, ses inconvnients et ses domaines d'applications. Le C# (Prononcez "C charpe" ou "ci charpe" l'anglaise), vous en avez peut-tre entendu parler autour dun caf, ou bien rencontr un dveloppeur qui en vantait les mrites ou peut-tre vu une offre demploi intressante sur le sujet qui sait ? Bref, vous avez envie de dcouvrir et d'apprendre le C#. Cest justement lobjectif que se donne ce tutoriel. Il est rserv aux dbutants dans la mesure o nous allons aborder ce sujet comme si nous nen avions jamais entendu parler mais il conviendra aussi aux personnes souhaitant approfondir leurs connaissances sur ce sujet. Peut-tre qu'il y en a parmi vous qui connaissent dj le C, le C++ ou Java. Cela pourra vous aider apprendre plus rapidement, mais ce n'est absolument pas grave si vous n'avez jamais fait de programmation avant.

En lisant les chapitres les uns aprs les autres, vous : commencerez dcouvrir ce qu'est vraiment le C# verrez les applications informatiques que nous pouvons raliser avec et comment ce langage s'intgre dans un ensemble plus important apprendrez rellement la syntaxe du C# dcouvrirez comment travailler avec des donnes afin de manipuler des fichiers ou de lire et crire dans une base de donnes Ltude ne sera pas exhaustive tellement il y a des sujets diffrents rattachs mais elle fournira un point dentre complet pour pouvoir tre efficace avec le C#. Mais plus important encore, lorsque vous aurez lu et pratiqu lensemble de ce tutoriel, vous serez capable de crer des applications informatiques de plusieurs sortes en utilisant le C#. Joli programme nest-ce pas ? Alors, enfilez votre tenue de combat et attaquons tout de suite le tutoriel !

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

5/381

Ce cours vous plat ? Si vous avez aim ce cours, vous pouvez retrouver le livre "Apprenez dvelopper en C#" en vente sur le Site du Zro, en librairie et dans les boutiques en ligne. V ous y trouverez ce cours adapt au format papier avec un chapitre et une prface indits. V ous pouvez galement obtenir cet ouvrage au format eBook sur Amazon ou sur iTunes. Plus d'informations

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

6/381

Partie 1 : Les rudiments du langage C#

Introduction au C#
Dans ce tout premier chapitre, nous allons dcouvrir ce qu'est le C#, son histoire et son rapport avec le framework .NET. D'ailleurs, vous ne savez pas ce qu'est un framework ? Ce n'est pas grave, tout ceci sera expliqu ! Nous verrons dans ce chapitre ce que sont les applications informatiques et comment des langages de programmation volus comme le C# nous permettent de raliser de telles applications. Et ce n'est que le dbut alors ouvrez grands vos yeux, chaussez vos lunettes et explorons ce monde merveilleux !

Avant propos A qui sadresse ce tutoriel ?


Aux dbutants ! Pas besoin d'avoir fait du dveloppement avant pour suivre ce tutoriel ! Je vais donc faire de mon mieux pour dtailler au maximum mes explications, c'est promis. Mon but est rellement de rendre ce tutoriel accessible pour les dbutants. Bien sr, il y en a peut-tre parmi vous qui ont dj fait du C, du C++, du Java... Evidemment, si vous avez dj fait du dveloppement informatique, ce sera plus facile pour vous (surtout pour la premire partie qui prsente les bases du langage). Attention nanmoins de ne pas vouloir aller trop vite : le C# ressemble d'autres langages mais il a quand mme ses spcificits !

Esprit du tutoriel
Nous allons dcouvrir ensemble de nombreuses choses en apprenant dvelopper en C#. Il y aura bien entendu des TP pour vous faire pratiquer, afin que vous puissiez vous rendre compte de ce que vous tes capables de faire aprs avoir lu plusieurs chapitres plus thoriques. Nanmoins, je veux que vous soyez actifs ! Ne vous contentez pas de lire passivement mes explications, mme lorsque les chapitres sont plutt thoriques ! Testez les codes et les manipulations au fur et mesure. Essayez les petites ides que vous avez pour amliorer ou adapter lgrement le code. Sortez un peu des sentiers battus du tutoriel : cela vous fera pratiquer et vous permettra de dcouvrir rapidement si vous avez compris ou non le chapitre. Pas d'inquitude, si jamais vous bloquez sur quoi que ce soit qui n'est pas expliqu dans ce cours, la communaut qui sillonne les forums saura vous apporter son aide prcieuse.

Dure dapprentissage
Il faut compter plusieurs semaines pour lire, comprendre et assimiler ce tutoriel. Une fois assimiles toutes les notions prsentes, il vous faudra plusieurs mois pour atteindre un niveau solide en C#. Aprs tout, c'est en forgeant qu'on devient forgeron. D'ailleurs merci de m'informer du temps que vous a pris la lecture de ce cours pour que je puisse indiquer aux autres lecteurs une dure moyenne de lecture.

C'est tout ?
Non rassurez-vous, le tutoriel est loin d'tre fini, vous ne voyez donc pas toutes les parties. V ous dcouvrirez dans ce tutoriel le dbut des rudiments du dveloppement en C#. Petit petit je complterai le tutoriel pour ajouter la suite des rudiments du langage. Ensuite, je prsenterai la programmation oriente objet et comment en faire avec le C#. Enfin, pour aller plus loin, nous tudierons l'accs aux donnes et d'autres surprises encore. Le dbut de ce cours sera plutt thorique. Pour savoir coder, il faut commencer par apprendre les bases du langage, c'est un passage oblig. Petit petit j'introduirai la pratique pour illustrer certains points importants ; cela vous permettra de mieux comprendre des fonctionnements et surtout de bien mmoriser le cours.

Allez plus loin !


N'hsitez pas regarder d'autres tutoriels portant sur le sujet. Il est toujours bon de diversifier ses sources pour avoir diffrentes approches du sujet.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

7/381

De manire gnrale, je vous recommande de ne pas hsiter tester les codes que je prsenterai au fur et mesure. Surtout, si vous avez des ides pour les amliorer un peu, faites-le ! Ca ne marchera pas tous les coups, mais cela vous fera beaucoup plus progresser que vous ne le pensez ! Ne comptez donc pas uniquement sur les TP pour pratiquer, ce serait dommage. Sachez aussi que je suis ouvert toutes remarques, critiques, questions, ... portant sur ce tutoriel. N'hsitez donc pas poster des commentaires, surtout si votre message peut tre utile pour d'autres personnes. Par contre, veuillez ne pas m'envoyer de MP, sauf en cas de force majeure, parce que je n'aurai pas le temps de vous rpondre individuellement, et que s'il s'agit d'une demande d'aide, les forums sont l pour a et on vous y rpondra plus rapidement que moi.

Qu'est-ce que le C# ?
Le C# est un langage de programmation cr par Microsoft en 2002. Un langage de programmation est un ensemble dinstructions, c'est--dire un ensemble de mots qui permettent de construire des applications informatiques. Ces applications informatiques peuvent tre de beaucoup de sortes, par exemple une application Windows, comme un logiciel de traitement de texte ou une calculatrice ou encore un jeu de cartes. On les appelle galement des clients lourds. Il est galement possible de dvelopper des applications web, comme un site de-commerce, un intranet, Nous pourrons accder ces applications grce un navigateur internet que lon appelle un client lger. Toujours grce un navigateur internet, nous pourrons dvelopper des clients riches. Ce sont des applications qui se rapprochent dune application Windows mais qui fonctionnent dans un navigateur. Bien dautres types d'applications peuvent tre crites avec le C#, citons encore le dveloppement dapplications mobiles sous Windows phone 7, de jeux ou encore le dveloppement de web services Nous verrons un peu plus en dtail en fin de tutoriel comment raliser de telles applications. Chacun de ces domaines ncessite un tutoriel entier pour tre compltement trait, aussi nous nous initierons ces domaines sans aller trop loin non plus. Le C# est un langage dont la syntaxe ressemble un peu au C++ ou au Java qui sont dautres langages de programmation trs populaires. Le C# est le langage phare de Microsoft. Il fait partie dun ensemble plus important. Il est en fait une brique de ce quon appelle le Framework .NET . Gardons encore un peu de suspens sur ce qu'est le framework .NET, nous dcouvrirons ce que c'est un peu plus loin dans le tutoriel.

Comment sont cres les applications informatiques ? Une application informatique : qu'est-ce que c'est ?
Comme vous le savez, votre ordinateur excute des applications informatiques pour effectuer des tches. Ce sont des logiciels comme : Un traitement de texte Un navigateur internet Un jeu vido ... V otre ordinateur ne peut excuter ces applications informatiques que si elles sont crites dans le seul langage qu'il comprend, le binaire. Techniquement, le binaire est reprsent par une suite de 0 et de 1.

Il n'est bien sr pas raisonnablement possible de raliser une grosse application en binaire, c'est pour a qu'il existe des langages de programmation qui permettent de simplifier l'criture d'une application informatique.

Comment crer des programmes "simplement" ?


www.siteduzero.com

Partie 1 : Les rudiments du langage C#

8/381

Je vais vous expliquer rapidement le principe de fonctionnement des langages "traditionnels" comme le C et le C++, puis je vous prsenterai le fonctionnement du C#. Comme le C# est plus rcent, il a t possible d'amliorer son fonctionnement par rapport au C et au C++ comme nous allons le voir.

Langages traditionnels : la compilation


Avec des langages traditionnels comme le C et le C++, on crit des instructions simplifies, lisibles par un humain comme : Code : C printf("Bonjour");

Ce n'est pas vraiment du franais, mais c'est quand mme beaucoup plus simple que le binaire et on comprend globalement avec cet exemple que l'on va afficher le mot Bonjour. Bien entendu, l'ordinateur ne comprend pas ces instructions. Lui, il veut du binaire, du vrai. Pour obtenir du binaire partir d'un code crit en C ou C++, on doit effectuer ce qu'on appelle une compilation. Le compilateur est un programme qui traduit le code source en binaire excutable :

Cette mthode est efficace et a fait ses preuves. De nombreuses personnes dveloppent toujours en C et C++ aujourd'hui. Nanmoins, ces langages ont aussi un certain nombre de dfauts dus leur anciennet. Par exemple, un programme compil (binaire) ne fonctionne que sur la plateforme pour laquelle il a t compil. Cela veut dire que si vous compilez sous Windows, vous obtenez un programme qui fonctionne sous Windows uniquement (et sur un type de processeur particulier). Impossible de le faire tourner sous Mac OS X ou Linux simplement, moins de le recompiler sous ces systmes d'exploitation (et d'effectuer au passage quelques modifications).

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

9/381

Les programmes binaires ont ce dfaut : ils ne fonctionnent que pour un type de machine. Pour les dveloppeurs qui crivent le code, c'est assez fastidieux grer.

Langages rcents : le code manag


Les langages rcents, comme le C# et le Java, rsolvent ce problme de compatibilit tout en ajoutant de nombreuses fonctionnalits apprciables au langage, ce qui permet de raliser des programmes beaucoup plus efficacement. La compilation en C# ne donne pas un programme binaire, contrairement au C et au C++. Le code C# est en fait transform dans un langage intermdiaire (appel CIL ou MSIL) que l'on peut ensuite distribuer tout le monde. Ce code, bien sr, n'est pas excutable lui-mme, car l'ordinateur ne comprend que le binaire. Regardez bien ce schma pour comprendre comment cela fonctionne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

10/381

Le code en langage intermdiaire (CIL) correspond au programme que vous allez distribuer. Sous Windows, il prend l'apparence d'un .exe comme les programmes habituels, mais il ne contient en revanche pas de binaire. Lorsqu'on excute le programme CIL, celui-ci est lu par un autre programme (une machine analyser les programmes, appele CLR) qui le compile cette fois en vrai programme binaire. Cette fois, le programme peut s'excuter, ouf ! Ca complique bien les choses quand mme ! Est-ce bien utile ?

Cela offre beaucoup de souplesse au dveloppeur. Le code en langage intermdiaire (CIL) peut tre distribu tout le monde. Il suffit d'avoir install la machine CLR sur son ordinateur, qui peut alors lire les programmes en C# et les compiler " la vole" en binaire. Avantage : le programme est toujours adapt l'ordinateur sur lequel il tourne. La CLR vrifie aussi la scurit du code ; ainsi en C du code mal pens (par exemple une mauvaise utilisation des pointeurs) peut entraner des problmes pour votre PC, ce que vous risquez beaucoup moins avec le C#. De plus, la CLR dispose du JIT debugger qui permet de lancer Visual Studio si une erreur survient dans un programme .NET pour voir ce qui a caus cette erreur. On parle de code manag. Cette complexit ralentit lgrement la vitesse d'excution des programmes (par rapport au C ou au C++), mais la diffrence est aujourd'hui vraiment ngligeable par rapport aux gains que cela apporte. Donc, en thorie, il est possible d'utiliser n'importe quelle application compile en langage intermdiaire partir du moment o il y a une implmentation du CLR disponible. En ralit, il n'y a que sous Windows qu'il existe une implmentation complte du CLR. Il existe cependant une implmentation partielle sous Linux : Mono. Cela veut dire que si votre programme utilise des fonctionnalits qui ne sont pas couvertes par Mono, il ne fonctionnera pas. En conclusion, dans la pratique, le .NET est totalement exploitable sous Windows, ailleurs non.

Excutables ou assemblages ?
J'ai dit juste au dessus que le C# tait compil en langage intermdiaire et qu'on le retrouve sous la forme d'un .exe comme les programmes habituels. C'est vrai ! (Je ne mens jamais ).

Par contre, c'est un peu incomplet. Il est possible de crer des programmes (.exe) qui pourront directement tre excut par le CLR, mais il est galement possible de crer des bibliothques sous la forme d'un fichier possdant l'extension .dll . On appelle ces deux formes de programmes des assemblages, mais on utilise globalement toujours le mot anglais assembly . Les fichiers .exe sont des assemblys de processus Les fichiers .dll sont des assemblys de bibliothques Concrtement, cela signifie que le fichier .exe servira lancer une application et qu'une dll pourra tre partage entre plusieurs applications .exe afin de rutiliser du code dj crit. Nous verrons un peu plus loin comment ceci est possible. Il est noter qu'un raccourci est souvent fait avec le terme assembly. On a tendance voir que le mot assembly sert dsigner uniquement les bibliothques dont l'extension est .dll.

Qu'est-ce que le framework .NET ?


J'ai commenc vous parler du C# qui tait une brique du framework .NET. Il est temps d'en savoir un peu plus sur ce fameux framework. Commenons par le commencement : comment cela se prononce ?

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Citation : Shakespeare DOTTE NETTE

11/381

Citation : maitre Capello POINT NETTE

Je vous accorde que le nom est bizarre, point trop net pourrions-nous dire Surtout que le nom peut tre trompeur. Avec lomniprsence dinternet, son abrviation (net) ou encore des noms de domaines (.net), on pourrait penser que le framework .NET est un truc ddi internet. Que nenni. Nous allons donc prciser un peu ce quest le framework .NET pour viter les ambigits.

Premire chose savoir, quest-ce quun framework ?

Pour simplifier, on peut dire quun framework est une espce de grosse boite fonctionnalits qui va nous permettre de raliser des applications informatiques de toutes sortes.

En fait, cest la combinaison de ce framework et du langage de programmation C# qui va nous permettre de raliser ces applications informatiques.

Le framework .NET est un framework cr par Microsoft en 2002, en mme temps que le C#, qui est principalement ddi la ralisation dapplications fonctionnant dans des environnements Microsoft. Nous pourrons par exemple raliser des programmes qui fonctionnent sous Windows, ou bien des sites web ou encore des applications qui fonctionnent sur tlphone mobile, etc. Disons que la ralisation dune application informatique, cest un peu comme un chantier (je dis pas a parce que c'est toujours en retard, mme si c'est vrai ). Il est possible de construire diffrentes choses, comme une maison, une piscine, une terrasse, etc. Pour raliser ces constructions, nous allons avoir besoin de matriaux, comme des briques, de la ferraille, etc. Certains matriaux sont communs toutes les constructions (fer, vis, ) et dautres sont spcifiques certains domaines (pour construire une piscine, je vais avoir besoin dun liner par exemple). On peut voir le framework .NET comme ces matriaux, cest un ensemble de composants que lon devra assembler pour raliser notre application. Certains sont spcifiques pour la ralisation dapplications web, dautres pour la ralisation dapplications Windows, etc. Pour raliser un chantier, nous allons avoir besoin doutils pour manipuler les matriaux. Qui envisagerait de visser une vis avec les doigts ou de poser des parpaings sans les coller avec du mortier ? Cest la mme chose pour une application informatique, pour assembler notre application, nous allons utiliser un langage de programmation : le C#. A lheure o jcris ces lignes, le C# est en version 4 ainsi que le framework .NET. Ce sont des versions stables et utilises par beaucoup de personnes. Chaque version intermdiaire a apport son lot dvolutions. Le framework .NET et le C# sont en perptuelle volution preuve de la dynamique apporte par Microsoft. Cest tout ce quil y a savoir pour linstant, nous reviendrons un peu plus en dtail sur le framework .NET dans les chapitres suivants. Pour lheure, il est important de retenir que cest grce au langage de programmation C# et grce aux composants du framework .NET que nous allons pouvoir dvelopper des applications informatiques.

En rsum
Le C# est un langage de programmation permettant dutiliser le framework .NET. Cest le langage phare de Microsoft. Le framework .NET est une norme bote fonctionnalits permettant la cration dapplications. Le C# permet de dvelopper des applications de toutes sortes, excutables par le CLR qui traduit le MSIL en binaire. Il est possible de crer des assemblys de deux sortes : des assemblys de processus excutables par le CLR et des

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


assemblys de bibliothques.

12/381

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

13/381

Crer un projet avec Visual C# 2010 express


Dans ce chapitre nous allons faire nos premiers pas avec le C#. Nous allons dans un premier temps installer et dcouvrir les outils qui nous seront ncessaires pour raliser des applications informatiques avec le C#. Nous verrons comment dmarrer avec ces outils et la fin de ce chapitre, nous serons capables de crer un petit programme qui affiche du texte simple et nous aurons commenc nous familiariser avec lenvironnement de dveloppement. Il faut bien commencer par les bases, mais vous verrez comme cela peut tre gratifiant darriver enfin faire un petit quelque chose. Allez, cest parti !

Que faut-il pour dmarrer ?


Jespre vous avoir donn envie de dmarrer lapprentissage du C#, cependant, il nous manque encore quelque chose pour pouvoir sereinement attaquer cet apprentissage. Bien sr, vous allez avoir besoin dun ordinateur, mais a priori, vous lavez dj Sil nest pas sous Windows, mais sous linux, vous pouvez utiliser Mono qui va permettre dutiliser le C# sous linux. Cependant, Mono nest pas aussi complet que le C# et le framework .NET sous Windows, en lutilisant vous risquez de passer ct de certaines parties du tutoriel. Pour reprendre la mtaphore du chantier, on peut dire quil va galement nous manquer un chef de chantier. Il nest pas forcment ncessaire en thorie, mais dans la pratique il se rvle indispensable pour mener bien son chantier. Ce chef de chantier cest en fait loutil de dveloppement. Il va nous fournir les outils pour orchestrer nos dveloppements. Cest entre autres : Un puissant diteur Un compilateur Un environnement dexcution

Lditeur de texte va nous servir crer des fichiers contenant des instructions en langage C#. Le compilateur va servir transformer ces fichiers en une suite d'instructions comprhensibles par l'ordinateur, comme nous l'avons dj vu. Le moteur dexcution va permettre de faire les actions informatiques correspondantes (afficher une phrase, ragir au clic de la souris, etc.), c'est le CLR dont on a dj parl. Enfin, nous aurons besoin dune base de donnes. Nous y reviendrons plus en dtail ultrieurement, mais la base de donnes est un endroit o seront stockes les donnes de notre application. Cest un lment indispensable mesure que lapplication grandit.

Installer Visual C# 2010 express


Nous avons donc besoin de notre chef de chantier, loutil de dveloppement. Cest un logiciel qui va nous permettre de crer des applications et qui va nous fournir les outils pour orchestrer nos dveloppements. La gamme de Microsoft est riche en outils professionnels de qualit pour le dveloppement, notamment grce Visual Studio. Notez que cet outil de dveloppement se nomme galement un IDE pour Integrated Development Environment ce qui signifie Environnement de dveloppement intgr .

Nous aurons recours au terme IDE rgulirement. Pour apprendre et commencer dcouvrir l'environnement de dveloppement, Microsoft propose gratuitement Visual Studio dans sa version express. Cest une version allge de lenvironnement de dveloppement qui permet de faire plein de choses, mais avec des outils en moins par rapport aux versions payantes. Rassurez-vous, ces versions gratuites sont trs fournies et permettent de faire tout ce dont on a besoin pour apprendre le C# et suivre ce tutoriel. Pour raliser des applications d'envergure, il pourra cependant tre judicieux d'investir dans l'outil complet et ainsi bnficier de fonctionnalits complmentaires qui permettent d'amliorer, de faciliter et d'industrialiser les dveloppements. Pour dvelopper en C# gratuitement et crer des applications Windows, nous allons avoir besoin de Microsoft Visual C# 2010 Express que vous pouvez tlcharger en vous rendant sur cette page. Pour rsumer :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

14/381

Visual Studio est la version payante de l'outil de dveloppement. Microsoft Visual C# 2010 Express est une version allge et gratuite de Visual Studio, ddie au dveloppement en C#. Exactement ce qu'il nous faut Cliquez sur Visual C# 2010 Express et choisissez la langue qui vous convient. Puis cliquez sur Tlchargez.

Une fois lexcutable tlcharg, il ne reste plus qu le lancer et linstallation dmarre :

Cliquez sur Suivant pour dmarrer linstallation :

V ous devez prsent lire la licence d'utilisation du logiciel et l'accepter pour pouvoir continuer l'installation :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

15/381

Une application sans donnes, c'est plutt rare. C'est un peu comme un site d'e-commerce sans produits, un traitement de texte sans fichiers ou le site du zro sans tutoriel. On risque de vite s'ennuyer . Heureusement, le programme dinstallation nous propose dinstaller Microsoft SQL Server 2008 express Service Pack 1 . Microsoft propose en version gratuite un serveur de base de donnes allg. Il va nous permettre de crer facilement une base de donnes et de lutiliser depuis nos applications en C#. Nous lavons dj voqu et nous y reviendrons plus en dtail dans un chapitre ultrieur mais une base de donnes est un norme endroit o sont stockes les donnes de notre application.

Nous avons galement voqu dans l'introduction qu'il tait possible de raliser des applications qui ressemblent des applications Windows mais dans un navigateur, que nous avons appel clients riches . Silverlight va justement permettre de crer ce genre d'application. Cochez donc tout pour installer Silverlight et Sql Server et cliquez sur suivant :

Cliquez sur Installer en changeant ventuellement le dossier d'installation :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

16/381

L'installation dmarre (vous devez tre connect Internet) :

Une fois l'installation termine cliquez sur Quitter.

A lheure o jcris ces lignes, il existe un service pack pour visual studio, le service pack 1. Cest un ensemble de corrections

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


qui permettent damliorer la stabilit du logiciel. Je vous invite tlcharger et installer ce service pack. V ous voil avec votre copie de Visual C# express qui va vous permettre de crer des programmes en C# gratuitement et facilement. L'installation de l'outil de dveloppement est termine.

17/381

Notez que, bien que gratuite, vous aurez besoin denregistrer votre copie de Visual C# express avant 30 jours. Cest une opration rapide et ncessitant un compte Windows Live. Aprs cela, vous pourrez utiliser Visual C# express sans retenues.

En rsum, nous avons install un outil de dveloppement, Visual C# 2010 dans sa version express et une base de donnes, SQL Server express 2008. Nous avons tous les outils ncessaires et nous allons pouvoir dmarrer (enfin !) l'apprentissage et la pratique du C#.

Dmarrer Visual C# 2010 Express


Nous allons vrifier que l'installation de Visual C# express a bien fonctionn. Et pour ce faire, nous allons le dmarrer et commencer prendre en main ce formidable outil de dveloppement. Il vous semblera surement trs complexe au dbut mais vous allez voir, si vous suivez ce tutoriel pas pas, vous allez apprendre les fonctionnalits indispensables. Elles seront illustres par des copies d'crans vous permettant de plus facilement vous y retrouver. A force dutiliser Visual C# express, vous verrez que vous vous sentirez de plus en plus laise et peut-tre oserezvous aller fouiller dans les menus ? Commencez par dmarrer Visual C# 2010 Express. Le logiciel souvre sur la page de dmarrage de Visual C# 2010 Express :

Les deux zones entoures de rouge permettent respectivement de crer un nouveau projet et daccder aux anciens projets dj crs. Dans ce deuxime cas, comme je viens dinstaller le logiciel, la liste est vide.

Crer un projet
Commenons par crer un nouveau projet en cliquant dans la zone rouge. Cette commande est galement accessible via le menu Fichier > Nouveau > Projet Un projet va contenir les lments de ce que lon souhaite raliser. Cela peut tre par exemple une application web, une application Windows, etc Le projet est aussi un container de fichiers et notamment dans notre cas de fichiers en langage C# qui vont permettre de construire ce que lon souhaite raliser. Le projet est en fait reprsent par un fichier dont lextension est .csproj. Son contenu dcrit les paramtres de configuration correspondant ce que lon souhaite raliser et les fichiers qui composent le projet. Crons donc un nouveau projet. La fentre de cration de nouveau projet souvre et nous avons plusieurs possibilits de choix. Nous allons dans un premier temps aller dans Visual C# pour choisir de crer une Application console.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

18/381

noter que si vous navez install que Visual C# express, vous aurez la mme fentre que moi. Si vous disposez de la version payante de Visual Studio, alors la fentre sera surement plus garnie. De mme, il y aura plus de choses si vous avez install dautres outils de la gamme Express.

Ce que nous faisons ici, cest utiliser ce quon appelle un modle (plus couramment appel par son quivalent anglais : template ) de cration de projet. Si vous naviguez lintrieur des diffrents modles, vous pourrez constater que Visual C# nous propose des modles de projets plus ou moins compliqus. Ces modles sont trs utiles pour dmarrer un projet car toute la configuration du projet est dj faite. Le nombre de modles peut tre diffrent en fonction de votre version de Visual Studio ou du nombre de versions express installes. Lapplication Console est la forme de projet pouvant produire une application excutable la plus simple. Elle permet de raliser un programme qui va sexcuter dans la console noire qui ressemble une fentre ms-dos, pour les dinosaures comme moi qui ont connu cette poque A noter que les projets de type Bibliothque de classes permettent de gnrer des assemblys de bibliothques (.dll). Dans cette console, nous allons pouvoir notamment afficher du texte simple. Ce type de projet est parfait pour dmarrer lapprentissage du C# car il ny a besoin que de savoir comment afficher du texte pour commencer alors que pour raliser une application graphique par exemple, il y a beaucoup dautres choses savoir. En bas de la fentre de cration de projet, nous avons la possibilit de choisir un nom pour le projet, ici ConsoleApplication1. Changeons le nom de notre application, par exemple "MaPremiereApplication", dans la zone correspondante. Cliquons sur OK pour valider la cration de notre projet.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

19/381

Visual C# Express cre alors pour nous les fichiers composant une application console vide, qui utilise le C# comme langage et que nous avons nomm MaPremiereApplication. Avant toute chose, nous allons enregistrer le projet. Allons dans le menu Fichier > Enregistrer (ou utiliser le raccourci bien connu ctrl+s) :

Visual C# Express nous ouvre la fentre denregistrement de projet :

Nous pouvons donner un nom, prciser un emplacement o nous souhaitons que les fichiers soient enregistrs et un nom de solution. Une case cocher pr-coche nous propose de crer un rpertoire pour la solution. Cest ce que nous allons faire et cliquons sur Enregistrer. noter que pour les versions payantes de Visual Studio, le choix de l'emplacement et le nom de la solution sont renseigner au moment o l'on cre le projet. Une diffrence subtile

Analyse rapide de lenvironnement de dveloppement et du code gnr


Allons dans lemplacement renseign (ici c:\users\nico\documents\visual studio 2010\Projects), nous pouvons constater que Visual C# Express a cr un rpertoire MaPremiereApplication, cest le fameux rpertoire pour la solution quil nous a propos de crer. Dans ce rpertoire, nous remarquons notamment un fichier MaPremiereApplication.sln. Cest ce qu'on appelle le fichier de solution ; il sagit juste dun container de projets qui va nous permettre de visualiser nos projets dans visual C# express.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

20/381

En loccurrence, pour linstant, nous avons un seul projet dans la solution: lapplication MaPremiereApplication, que nous retrouvons dans le sous rpertoire MaPremiereApplication et qui contient notamment le fichier de projet : MaPremiereApplication.csproj. Le fichier dcrivant un projet crit en C# est prfix par cs (csproj).

Il y a encore un fichier digne dintrt (pour linstant) dans ce rpertoire, il sagit du fichier Program.cs. Les fichiers dont lextension est .cs contiennent du code C#, cest dans ce fichier que nous allons commencer taper nos premires lignes de code noter que l'ensemble des fichiers contenant des instructions crites dans un langage de programmation est appel le code source . Par extension, le code correspond des instructions crites dans un langage de programmation. Si nous retournons dans linterface de Visual C# express, nous pouvons retrouver quelque chose comme a :

La zone verte numro 1 contient les diffrents fichiers ouverts sous la forme dun onglet. On voit que par dfaut, Visual C# nous a cr et ouvert le fichier Program.cs. Dans la zone rouge numro 2, cest lditeur de code. Il affiche le contenu du fichier ouvert. Nous voyons des mots que nous ne comprenons pas encore. Cest du code qui a t automatiquement gnr par Visual C#. Nous pouvons observer que les mots sont de diffrentes couleurs. En effet, lditeur Visual C# express possde ce quon appelle une coloration syntaxique, c'est-dire que certains mots cls sont colors dune couleur diffrente en fonction de leur signification ou de leur contexte afin de nous permettre de nous y retrouver plus facilement. La zone numro 3 en violet est lexplorateur de solutions, cest ici que lon voit le contenu de la solution sur laquelle nous travaillons en ce moment. En loccurrence, il sagit de la solution MaPremiereApplication qui contient un unique projet MaPremiereApplication . Ce projet contient plusieurs sous lments : Properties : contient des proprits de lapplication, on ne sen occupe pas pour linstant Rfrences : contient les rfrences de lapplication, on ne sen occupe pas pour linstant Program.cs est le fichier qui a t gnr par Visual C# et qui contient le code C#. Il nous intresse fortement !! La zone 4 en brun est la zone contenant les proprits de ce sur quoi nous travaillons en ce moment. Ici, nous avons le curseur positionn sur le projet, il ny a pas beaucoup dinformations except le nom du fichier de projet. Nous aurons loccasion de revenir sur cette fentre plus tard.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

21/381

La zone 5 en jaune nest pas affiche au premier lancement, elle contient la liste des erreurs, des avertissements et des messages de notre application. Nous verrons comment lafficher un peu plus bas. La zone 6 en noir est la barre d'outils, elle possde plusieurs boutons que nous pourrons utiliser, notamment pour excuter notre application.

Ecrire du texte dans notre application


Allons donc dans la zone 2 rserve ldition de notre fichier Program.cs qui est le fichier contenant le code C# de notre application. Les mots prsents dans cette zone sont ce quon appelle des instructions de langage. Elles vont nous permettre dcrire notre programme. Nous reviendrons plus loin sur ce que veulent dire les instructions qui ont t gnres par Visual C#, pour linstant, rajoutons simplement linstruction suivante aprs l'accolade ouvrante : Code : C# Console.WriteLine("Hello World !!");

de manire avoir : Code : C# static void Main(string[] args) { Console.WriteLine("Hello World !!"); }

Nous venons dcrire une instruction qui va afficher la phrase Hello World !!, pour linstant vous avez juste besoin de savoir a. Nous tudierons plus en dtail ultrieurement quoi cela correspond exactement.

L'excution du projet
Ca y est ! Nous avons crit notre premier code qui affiche un message trs populaire. Mais pour le moment, a ne fait rien. On veut voir ce que a donne !!!

Comme je vous comprends. La premire chose faire est de transformer le langage C# que nous venons dcrire en programme excutable. Cette phase sappelle la gnration de la solution sous Visual C#. On lappelle souvent la compilation ou en anglais le build . Allez dans le menu Dboguer et cliquez sur Gnrer la solution :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

22/381

Visual C# lance alors la gnration de la solution et on voit dans la barre des taches en bas gauche quil travaille jusqu nous indiquer que la gnration a russi :

Si nous allons dans le rpertoire contenant la solution, nous pouvons voir dans le rpertoire MaPremiereApplication\MaPremiereApplication\bin\Release quil y a deux fichiers :

MaPremiereApplication.exe MaPremiereApplication.pdb

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

23/381

Le premier est le fichier excutable, possdant lextension .exe, qui est le rsultat du processus de gnration. Il sagit bien de notre application. Le second est un fichier particulier quil nest pas utile de connaitre pour linstant, nous allons lignorer. Excutons notre application en lanant le fichier excutable depuis lexplorateur de fichiers. Dception, nous voyons peine un truc noirtre qui saffiche et qui se referme immdiatement. Que sest-il pass ? En fait, lapplication sest lance, a affich notre message et sest termine immdiatement. Et tout a un brin trop rapidement a ne va pas tre pratique tout a. Heureusement, Visual C# express arrive la rescousse. Retournons dans notre IDE prfr. Nous allons ajouter un bouton dans la barre doutils. Javoue ne pas comprendre pourquoi ce bouton est manquant dans linstallation par dfaut. Nous allons remdier ce problme en cliquant sur la petite flche qui est ct de la barre doutils tout droite et qui nous ouvre le menu droulant permettant dajouter ou supprimer des boutons et cliquez sur Personnaliser :

Cliquez sur Ajouter une commande :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

24/381

Allez dans la catgorie dboguer et choisissez Excuter sans dbogage puis cliquez sur OK :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

25/381

Enfin, fermez la fentre. V ous avez dsormais un nouveau bouton dans la barre doutils :

Si vous avez eu la flemme dajouter le bouton prcdemment, vous pouvez utiliser le raccourci ctrl+F5 ou bien cliquer sur ce nouveau bouton pour excuter lapplication depuis Visual c#. La console souvre nous dlivrant le message tant attendu :

Le message est dsormais visible car Visual C# nous demande dappuyer sur une touche pour que lapplication se termine, ce qui nous laisse donc le temps dapprcier lexcution de notre superbe programme. Wahouu, a y est, notre premire application en C# !!! Je suis fier de nous, mais nous nallons pas en rester l, nous sommes dsormais fin pars pour apprendre le C#.

En rsum
Visual C# Express est loutil de dveloppement gratuit de Microsoft permettant de dmarrer avec le C#. Visual Studio est loutil de dveloppement payant de Microsoft permettant dtre efficace dans le dveloppement dapplications .NET. Microsoft SQL Server Express est le moteur de base de donnes utilisable facilement avec Visual C# Express. Lenvironnement de dveloppement nous permet de crer du code C# qui sera contenu dans des projets, qui peuvent tre runis dans une solution.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

26/381

La syntaxe gnrale du C#
Nous allons aborder ici la syntaxe gnrale du langage de programmation C# dans le cadre dune application console. Il est en effet possible de crer plein de choses diffrentes avec le C# comme une application web, des jeux, etc. Dans cette optique, nous allons utiliser trs souvent linstruction : Console.WriteLine(""); que nous avons vue au chapitre prcdent et qui est une instruction ddie laffichage sur la console. Cest une instruction qui va savrer trs pratique pour notre apprentissage car nous pourrons avoir une reprsentation visuelle de ce que nous allons apprendre. Il est globalement rare quune application ne doive afficher que du texte, sans aucune mise en forme. V ous verrez en fin de tutoriel comment raliser des applications un peu plus volues graphiquement. Prparez vous, nous plongeons petit petit dans l'univers du C#. Dans ce chapitre, nous allons nous attaquer la syntaxe gnrale du C# et nous serons capable de reconnatre les lignes de code et de quoi elles se composent.

Ecrire une ligne de code


Les lignes de code crites avec le langage de dveloppement C# doivent scrire dans des fichiers dont lextension est .cs. Nous avons vu dans le chapitre prcdent que nous avons crit dans le fichier Program.cs qui est le fichier qui a t gnr par Visual C# lors de la cration du projet. Nous y avons notamment rajout une instruction permettant dafficher du texte. Les lignes de code C# se lisent et scrivent de haut en bas et de gauche droite, comme un livre normal. Aussi, une instruction crite avant une autre sera en gnral excute avant celle-ci. Attention, chaque ligne de code doit tre correcte syntaxiquement sinon le compilateur ne saura pas le traduire en langage excutable.

Par exemple, si la fin de mon instruction, je retire le point-virgule ou si jorthographie mal le mot WriteLine, jaurai :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

27/381

Visual C# Express me signale quil y a un problme en mettant en valeur un manque au niveau de la fin de linstruction et il me souligne galement le mot WritLine . Dans la fentre du bas, il mindique quil a deux erreurs et me donne des prcisions sur celles-ci avec ventuellement des pistes pour rsoudre ces erreurs. Si je tente de lancer mon application (raccourci ctrl+F5), Visual C# Express va tenter de compiler et dexcuter lapplication. Ceci ntant pas possible, il maffichera un message indiquant quil y a des erreurs.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

28/381

Ce sont des erreurs de compilation quil va falloir rsoudre si lon souhaite que lapplication console puisse sexcuter. Nous allons voir dans les chapitres suivant comment crire correctement des instructions en C#. Mais il est important de noter lheure actuelle que le C# est sensible la casse, ce qui veut dire que les majuscules comptent ! Ainsi le mot WriteLine et le mot WriTEline sont deux mots bien distincts et peuvent potentiellement reprsenter deux instructions diffrentes. Ici, le deuxime mot est incorrect car il nexiste pas. Rappelez-vous bien que la casse est dterminante pour que lapplication puisse compiler.

Le caractre de terminaison de ligne


En gnral, une instruction en code C# scrit sur une ligne et se termine par un point-virgule. Ainsi, linstruction que nous avons vue plus haut : Code : C# Console.WriteLine("Hello World !!");

se termine au niveau du point-virgule. Il aurait t possible de remplacer le code crit : Code : C# class Program { static void Main(string[] args) { Console.WriteLine("Hello World !!"); } }

par : Code : C# class Program {static void Main(string[] args) {Console.WriteLine("Hello World !!");}}

ou encore : Code : C# class Program { static void Main(string[] args) { Console .WriteLine("Hello World !!" } );

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

29/381

En gnral, pour que le code soit le plus lisible possible, on crit une instruction par ligne et on indente le code de faon ce que les blocs soient lisibles. Un bloc de code est dlimit par des accolades { et }. Nous y reviendrons plus tard.

Indenter signifie que chaque ligne de code qui fait partie dun mme bloc de code commence avec le mme retrait sur lditeur. Ce sont soit des tabulations, soit des espaces qui permettent de faire ce retrait.

Visual C# express nous aide pour faire correctement cette indentation quand nous crivons du code. Il peut galement remettre toute la page en forme avec la combinaison de touche : ctrl+k+ctrl+d. Dcortiquons prsent cette ligne de code : Code : C# Console.WriteLine("Hello World !!");

Pour simplifier, nous dirons que nous appelons la mthode WriteLine qui permet dcrire une chaine de caractres sur la Console.

Une mthode reprsente une fonctionnalit, crite avec du code, qui est utilisable par dautres bouts de code (par exemple, calculer la racine carre d'un nombre ou afficher du texte ...).

Linstruction "Hello World !!" reprsente une chaine de caractres et est passe en paramtre de la mthode Console.WriteLine laide des parenthses. La chaine de caractres est dlimite par les guillemets. Enfin, le point-virgule permet dindiquer que linstruction est termine et quon peut enchainer sur la suivante. Certains points ne sont peut-tre pas encore tout fait clairs, comme ce quest vraiment une mthode, ou comment utiliser des chaines de caractres, mais ne vous inquitez pas, nous allons y revenir plus en dtail dans les chapitres suivants et dcouvrir au fur et mesure les arcanes du C#.

Les commentaires
Pour faciliter la comprhension du code ou pour se rappeler un point prcis, il est possible de mettre des commentaires dans son code. Les commentaires sont ignors par le compilateur et nont quune valeur informative pour le dveloppeur. Dans un fichier de code C# (.cs), on peut crire des commentaires de 2 faons diffrentes : Soit en commenant son commentaire par /* et en le terminant par */ ce qui permet dcrire un commentaire sur plusieurs lignes. Soit en utilisant // et tout ce qui se trouve aprs sur la mme ligne est alors un commentaire.

Visual C# express colore les commentaires en vert pour faciliter leurs identifications. Code : C# /* permet d'afficher du texte sur la console */ Console.WriteLine("Hello World !!"); // ne pas oublier le point virgule

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

30/381

A noter qu'on peut commenter plusieurs lignes de code avec le raccourci clavier ctrl+k + ctrl+c et dcommenter plusieurs lignes de code avec le raccourci clavier ctrl+k+ctrl+u.

La compltion automatique
Visual C# express est un formidable outil qui nous facilite tout moment la tche, notamment grce la compltion automatique. La compltion automatique est le fait de proposer de complter automatiquement ce que nous sommes en train dcrire en se basant sur ce que nous avons le droit de faire. Par exemple, si vous avez cherch crire linstruction : Code : C# Console.WriteLine("Hello World !!");

vous avez pu constater que lors de lappui sur la touche C, Visual C# express nous affiche une fentre avec tout ce qui commence par C :

Au fur et mesure de la saisie, il affine les propositions pour se positionner sur la plus pertinente. Il est possible de valider la proposition en appuyant sur la touche Entre. Non seulement cela nous conomise des appuis de touches, paresseux comme nous sommes, mais cela nous permet galement de vrifier la syntaxe de ce que nous crivons et dobtenir galement une miniaide sur ce que nous essayons dutiliser.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

31/381

Ainsi, finies les fautes de frappe qui rsultent en une erreur de compilation ou les listes de mots cls dont il faut absolument retenir lcriture. De la mme faon, une fois que vous avez fini de saisir Console vous allez saisir le point . et Visual C# express va nous proposer toute une srie dinstruction en rapport avec le dbut de linstruction :

Nous pourrons ainsi facilement finir de saisir WriteLine et ceci sans erreur dcriture, ni problme de majuscule.

En rsum
Le code C# est compos dune suite dinstructions qui se terminent par un point virgule. La syntaxe dun code C# doit tre correcte sinon nous aurons des erreurs de compilation. Il est possible de commenter son code grce aux caractres // , /* et */ . Visual C# Express dispose dun outil puissant qui permet daider complter ses instructions : la compltion automatique.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

32/381

Les variables
Dans ce chapitre nous allons apprendre ce que sont les variables et comment ces lments indispensables vont nous rendre bien des services pour traiter de l'information susceptible de changer dans nos programmes informatiques. Nous continuerons en dcouvrant les diffrents types de variables et nous ferons nos premires manipulations avec elles. Soyez attentifs ce chapitre, il est vraiment fondamental de bien comprendre quoi servent les variables lors du dveloppement d'une application informatique.

Quest-ce quune variable ?


Comme tous les langages de programmations, le C# va pouvoir conserver des donnes grce des variables. Ce sont en fait des blocs de mmoire qui vont contenir des nombres, des chaines de caractres, des dates ou plein dautres choses. Les variables vont nous permettre deffectuer des calculs mathmatiques, denregistrer lge du visiteur, de comparer des valeurs, etc. On peut les comparer des petits classeurs possdant une tiquette. On va pouvoir mettre des choses dans ces classeurs, par exemple, je mets 30 dans le classeur tiquet ge de Nicolas et 20 dans le classeur ge de Jrmie . Si je veux connaitre lge de Nicolas, je nai qu regarder dans ce classeur pour obtenir 30. Je peux galement remplacer ce quil y a dans mon classeur par autre chose, par exemple changer 30 en 25. Je ne peux par contre pas mettre deux choses dans mon classeur, il na quun seul emplacement. Une variable est reprsente par son nom, caractrise par son type et contient une valeur. Le type correspond ce que la variable reprsente : un entier, une chaine de caractres, une date, etc

Par exemple, lge dune personne pourrait tre stocke sous la forme dun entier et accessible par la variable age , ce qui scrit en C# : Code : C# int age;

On appelle ceci la dclaration de la variable age . Le mot cl int permet dindiquer au compilateur que la variable age est un entier numrique. int correspond au dbut d integer qui veut dire entier en anglais. Ici, la variable age na pas t initialise, elle ne pourra pas tre utilise car le compilateur ne sait pas quelle valeur il y a dans la variable age. Pour linitialiser (on parle galement daffecter une valeur ) on utilisera loprateur gal ( = ). Code : C# int age; age = 30;

Notre variable age possde dsormais lentier numrique 30 comme valeur. Linitialisation dune variable peut galement se faire au mme moment que sa dclaration. Ainsi, on pourra remplacer le code prcdent par : Code : C# int age = 30;

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

33/381

Pour dclarer une variable en C#, on commence toujours par indiquer son type (int, ici un entier) et son nom (age). Il faudra imprativement affecter une valeur cette variable avec loprateur = , soit sur la mme instruction que la dclaration, soit un peu plus loin dans le code, mais dans tous les cas, avant lutilisation de cette variable. Nous pouvons tout moment demander la valeur contenue dans la variable age, par exemple : Code : C# int age = 30; Console.WriteLine(age); // affiche 30

Il est possible de modifier la valeur de la variable nimporte quel moment grce lemploi de loprateur = que nous avons aperu : Code : C# int age = 30; Console.WriteLine(age); // affiche 30 age = 20; Console.WriteLine(age); // affiche 20

V ous pouvez nommer vos variables peu prs nimporte comment, quelques dtails prs. Les noms de variables ne peuvent pas avoir le mme nom quun type. Il sera alors impossible dappeler une variable int. Il est galement impossible dutiliser des caractres spciaux, comme des espaces ou des caractres de ponctuation. De mme, on ne pourra pas nommer une variable en commenant par des chiffres. Il est par contre possible d'utiliser des accents dans les noms de variable, cependant ceci n'est pas recommand et ne fait pas partie des bonnes pratiques de dveloppement. En effet, il est souvent recommand de nommer ses variables en anglais (langue qui ne contient pas d'accents). V ous aurez not que je ne le fais pas volontairement dans ce tutoriel afin de ne pas rajouter une contrainte supplmentaire lors de la lecture du code. Mais libre vous de le faire . En gnral, une variable commence par une minuscule et si son nom reprsente plusieurs mots, on dmarrera un nouveau mot par une majuscule. Par exemple : Code : C# int ageDuVisiteur;

Cest ce quon appelle le camel case. Attention, suivant le principe de sensibilit la casse, il faut faire attention car ageduvisiteur et ageDuVisiteur seront deux variables diffrentes : Code : C# int ageduvisiteur = 30; int ageDuVisiteur = 20; Console.WriteLine(ageduvisiteur); // affiche 30 Console.WriteLine(ageDuVisiteur); // affiche 20

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

34/381

A noter un dtail qui peut paraitre vident, mais toutes les variables sont rinitialises chaque nouvelle excution du programme. Ds quon dmarre le programme, les classeurs sont vids, comme si on emmnageait dans des nouveaux locaux chaque fois. Il est donc impossible de faire persister une information entre deux excutions du programme en utilisant des variables. Pour ceci, on utilisera dautres solutions, comme enregistrer des valeurs dans un fichier ou dans une base de donnes. Nous y reviendrons ultrieurement.

Les diffrents types de variables


Nous avons vu juste au-dessus que la variable age pouvait tre un entier numrique grce au mot cl int. Le framework .NET dispose de beaucoup de types permettant de reprsenter beaucoup de choses diffrentes. Par exemple, nous pouvons stocker une chaine de caractres grce au type string. Code : C# string prenom = "nicolas";

ou encore un dcimal avec : Code : C# decimal soldeCompteBancaire = 100;

ou encore un boolean (qui reprsente une valeur vraie ou fausse) avec Code : C# bool estVrai = true;

Il est important de stocker des donnes dans des variables ayant le bon type.

On ne peut par exemple pas stocker le prnom "Nicolas" dans un entier. Les principaux types de base du framework .NET sont : Type byte short int long float double decimal char string bool Entier de 0 255 Entier de -32768 32767 Entier de -2147483648 2147483647 Entier de -9223372036854775808 9223372036854775807 Nombre simple prcision de -3,402823e38 3,402823e38 Nombre double prcision de -1,79769313486232e308 1,79769313486232e308 Nombre dcimal convenant particulirement aux calculs financiers (en raison de ses nombres significatifs aprs la virgule) Reprsente un caractre Une chaine de caractre Une valeur boolenne (vrai ou faux) Description

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

35/381

V ous verrez plus loin qu'il existe encore d'autres types dans le framework .NET et qu'on peut galement construire les siens.

Affectations, oprations, concatnation


Il est possible deffectuer des oprations sur les variables et entre les variables. Nous avons dj vu comment affecter une valeur une variable grce loprateur =. Code : C# int age = 30; string prenom = "nicolas";

Note : dans ce paragraphe, je vais vous donner plusieurs exemples daffectations. Ces affectations seront faites sur la mme instruction que la dclaration pour des raisons de concision. Mais ces exemples sont videmment fonctionnels pour des affectations qui se situent un endroit diffrent de la dclaration. En plus de la simple affectation, nous pouvons galement faire des oprations, par exemple : Code : C# int resultat = 2 * 3;

ou encore Code : C# int age1 = 20; int age2 = 30; int moyenne = (age1 + age2) / 2;

Les oprateurs + , * , / ou encore - (que nous navons pas encore utilis) servent bien videmment faire les oprations mathmatiques qui leur correspondent, savoir respectivement laddition, la multiplication, la division et la soustraction. V ous aurez donc surement devin que la variable resultat contient 6 et que la moyenne vaut 25. Il est noter que les variables contiennent une valeur qui ne peut voluer quen affectant une nouvelle valeur cette variable. Ainsi, si jai le code suivant : Code : C# int age1 = 20; int age2 = 30; int moyenne = (age1 + age2) / 2; age2 = 40;

la variable moyenne vaudra toujours 25 mme si jai chang la valeur de la variable age2 . En effet, lors du calcul de la moyenne, jai rang dans mon classeur la valeur 25 grce loprateur daffectation = et jai referm mon classeur. Le fait de changer la valeur du classeur age2 ninfluence en rien le classeur moyenne dans la mesure o il est ferm. Pour le modifier, il faudrait r-excuter lopration daffectation de la variable moyenne, en crivant nouveau linstruction de calcul, cest--dire : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


int age1 = 20; int age2 = 30; int moyenne = (age1 + age2) / 2; age2 = 40; moyenne = (age1 + age2) / 2;

36/381

Loprateur + peut galement servir concatner des chaines de caractres, par exemple : Code : C# string codePostal = "33000"; string ville = "Bordeaux"; string adresse = codePostal + " " + ville; Console.WriteLine(adresse); // affiche : 33000 Bordeaux

Dautres oprateurs particuliers existent que nous ne trouvons pas dans les cours de mathmatiques. Par exemple, loprateur ++ qui permet de raliser une incrmentation de 1, ou loprateur -- qui permet de faire une dcrmentation de 1. De mme, les oprateurs que nous avons dj vus peuvent se cumuler loprateur = pour simplifier une opration qui prend une variable comme oprande et cette mme variable comme rsultat. Par exemple : Code : C# int age age age age age age = 20; = age + 10; // age contient 30 (addition) = age++; // age contient 31 (incrmentation de 1) = age--; // age contient 30 (dcrmentation de 1) += 10; // quivalent age = age + 10 (age contient 40) /= 2; // quivalent age = age / 2 => (age contient 20)

Comme nous avons pu le voir dans nos cours de mathmatiques, il est possible de grouper des oprations avec des parenthses pour agir sur leurs priorits. Ainsi, linstruction prcdemment vue : Code : C# int moyenne = (age1 + age2) / 2;

effectue bien la somme des deux ges avant de les diviser par 2, car les parenthses sont prioritaires. Cependant, linstruction suivante : Code : C# int moyenne = age1 + age2 / 2;

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

37/381

aurait commenc par diviser lage2 par 2 et aurait ajout lage1, ce qui naurait plus rien voir avec une moyenne. En effet, la division est prioritaire par rapport laddition. Attention, la division ici est un peu particulire.

Prenons cet exemple : Code : C# int moyenne = 5 / 2; Console.WriteLine(moyenne);

Si nous l'excutons, nous voyons que moyenne vaut 2. 2 ? Si je me rappelle bien de mes cours de math ... c'est pas plutt 2.5 ?

Oui et non. Si nous divisions 5 par 2, nous obtenons bien 2.5. Par contre, ici nous divisons l'entier 5 par l'entier 2 et nous stockons le rsultat dans l'entier moyenne. Le C# ralise en fait une division entire, c'est--dire qu'il prend la partie entire de 2.5, c'est--dire 2. De plus, l'entier moyenne est incapable de stocker une valeur contenant des chiffres aprs la virgule. Il ne prendrait que la partie entire. Pour avoir 2.5, il faudrait utiliser le code suivant : Code : C# double moyenne = 5.0 / 2.0; Console.WriteLine(moyenne);

Ici, nous divisons deux doubles entre eux et nous stockons le rsultat dans un double . (Rappelez-vous, le type de donnes double permet de stocker des nombres virgule.) Le C# comprend qu'il s'agit de double car nous avons ajout un .0 derrire. Sans a, il considre que les chiffres sont des entiers.

Les caractres spciaux dans les chaines de caractres


En ce qui concerne laffectation de chaines de caractres, vous risquez davoir des surprises si vous tentez de mettre des caractres spciaux dans des variables de type string. En effet, une chaine de caractres tant dlimite par des guillemets " ", comment faire pour que notre chaine de caractres puisse contenir des guillemets ? Cest l quintervient le caractre spcial \ qui sera mettre juste devant le guillemet, par exemple le code suivant : Code : C# string phrase = "Mon prnom est \"Nicolas\""; Console.WriteLine(phrase);

affichera :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

38/381

Si vous avez test par vous-mme linstruction Console.WriteLine et enchain plusieurs instructions qui crivent des lignes, vous avez pu remarquer que nous passions la ligne chaque fois. Cest le rle de linstruction WriteLine qui affiche la chaine de caractres et passe la ligne la fin de la chane de caractres. Nous pouvons faire la mme chose en utilisant le caractre spcial \n . Il permet de passer la ligne chaque fois quil est rencontr. Ainsi, le code suivant : Code : C# string phrase = "Mon prnom est \"Nicolas\""; Console.WriteLine(phrase); Console.WriteLine("Passe\n\nla\nligne\n\n\n");

affichera :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

39/381

o nous remarquons bien les divers passages la ligne. V ous me diriez quon pourrait enchaner les Console.WriteLine et vous auriez raison. Mais les caractres spciaux nous permettent de faire dautres choses comme une tabulation par exemple grce au caractre spcial \t . Le code suivant : Code : C# Console.WriteLine("Choses faire :"); Console.WriteLine("\t - Arroser les plantes"); Console.WriteLine("\t - Laver la voiture");

permettra dafficher des tabulations, comme illustr ci-dessous :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

40/381

Nous avons vu que le caractre \ tait un caractre spcial et quil permettait de dire au compilateur que nous voulions lutiliser combin la valeur qui le suit, permettant d avoir une tabulation ou un retour la ligne. Comment pourrons-nous avoir une chaine de caractres qui contienne ce fameux caractre ? Le principe est le mme, il suffira de faire suivre ce fameux caractre spcial de lui-mme : Code : C# string fichier = "c:\\repertoire\\fichier.cs"; Console.WriteLine(fichier);

Ce qui donnera :

Pour ce cas particulier, il est galement possible dutiliser la syntaxe suivante en utilisant le caractre spcial @ devant la chaine de caractres : Code : C# string fichier = @"c:\repertoire\fichier.cs"; // contient : c:\repertoire\fichier.cs

Bien sur, nous pouvons stocker des caractres spciaux dans des variables pour faire par exemple : Code : C# string sautDeLigne = "\n"; Console.WriteLine("Passer" + sautDeLigne + "" + sautDeLigne + "la" + sautDeLigne + "ligne");

Dans ce cas, la variable sautDeLigne peut tre remplace par une espce de variable qui existe dj dans le framework .NET, savoir Environment.NewLine.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Ce qui permet davoir le code suivant : Code : C# Console.WriteLine("Passer" + Environment.NewLine + "" + Environment.NewLine + "la" + Environment.NewLine + "ligne");

41/381

permettant dafficher :

Notez qu'il est possible de passer la ligne lors de l'criture d'une instruction C# comme je l'ai fait dans le dernier bout de code afin d'amliorer la lisibilit. N'oubliez pas que c'est le point-virgule qui termine l'instruction.

Environment.NewLine ? Une espce de variable ? Quest-ce que cest que cette chose l ?

En fait, je triche un peu sur les mots. Pour faciliter la comprhension, on peut considrer que Environment.NewLine est une variable, au mme titre que la variable sautDeLigne que nous avons dfini. En ralit, cest un peu plus complexe quune variable. Nous dcouvrirons plus loin de quoi il sagit vraiment.

En rsum
Une variable est une zone mmoire permettant de stocker une valeur d'un type particulier. Le C# possde plein de types prdfinis, comme les entiers (int), les chanes de caractres (string), etc. On utilise l'oprateur = pour affecter une valeur une variable. Il est possible de faire des oprations entre les variables.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

42/381

Les instructions conditionnelles


Dans nos programmes C#, nous allons rgulirement avoir besoin de faire des oprations en fonction d'un rsultat prcdent. Par exemple, lors d'un processus de connexion une application, si le login et le mot de passe sont bons, alors nous pouvons nous connecter, sinon nous afficherons une erreur. Il s'agit de ce que l'on appelle une condition. Elle est value lors de l'excution et en fonction de son rsultat (vrai ou faux) nous ferons telle ou telle chose. Bien que relativement court, ce chapitre est trs important. N'hsitez pas le relire et vous entraner.

Les oprateurs de comparaison


Une condition se construit grce des oprateurs de comparaison. On dnombre plusieurs oprateurs de comparaisons, les plus courants sont : Oprateur == != > < >= <= && || ! Description Egalit Diffrence Suprieur Infrieur Suprieur ou gal Infrieur ou gal ET logique OU logique Ngation

Nous allons voir comment les utiliser en combinaison avec les instructions conditionnelles.

L'instruction "if"
Linstruction if permet dexcuter du code si une condition est vraie (if = si en anglais). Par exemple : Code : C# decimal compteEnBanque = 300; if (compteEnBanque >= 0) Console.WriteLine("Votre compte est crditeur");

Ici, nous avons une variable contenant le solde de notre compte en banque. Si notre solde est suprieur ou gal 0 alors nous affichons que le compte est crditeur. Pour afficher que le compte est dbiteur, on pourrait tester si la valeur de la variable est infrieure 0 et afficher que le compte est dbiteur : Code : C# decimal compteEnBanque = 300; if (compteEnBanque >= 0) Console.WriteLine("Votre compte est crditeur"); if (compteEnBanque < 0) Console.WriteLine("Votre compte est dbiteur");

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

43/381

Une autre solution est dutiliser le mot cl else, qui veut dire sinon en anglais. Si la valeur est vraie, alors on fait quelque chose, sinon, on fait autre chose , ce qui se traduit en C# par : Code : C# decimal compteEnBanque = 300; if (compteEnBanque >= 0) Console.WriteLine("Votre compte est crditeur"); else Console.WriteLine("Votre compte est dbiteur");

Il faut bien se rendre compte que linstruction if teste si une valeur est vraie (dans lexemple prcdent la comparaison compteEnBanque >= 0). On a vu rapidement dans les chapitres prcdents quil existait un type de variable qui permettait de stocker une valeur vraie ou fausse : le type bool, autrement appel boolen (boolean en anglais). Ainsi, il sera galement possible de tester la valeur dun boolen. Lexemple prcdent peut aussi scrire : Code : C# decimal compteEnBanque = 300; bool estCrediteur = (compteEnBanque >= 0); if (estCrediteur) Console.WriteLine("Votre compte est crditeur"); else Console.WriteLine("Votre compte est dbiteur");

noter que les parenthses autour de linstruction de comparaison sont facultatives, je les ai crites ici pour clairement identifier que la variable estCrediteur va contenir une valeur qui est le rsultat de lopration de comparaison compte en banque est suprieur ou gal 0 , en loccurrence vrai. V dautres exemples pour vous permettre dapprhender plus prcisment le fonctionnement du type bool : oici Code : C# int age = 30; bool estAgeDe30Ans = age == 30; Console.WriteLine(estAgeDe30Ans); // affiche True bool estSuperieurA10 = age > 10; Console.WriteLine(estSuperieurA10); // affiche True bool estDifferentDe30 = age != 30; Console.WriteLine(estDifferentDe30); // affiche False

Un type bool peut prendre deux valeurs, vrai ou faux, qui scrivent avec les mots cls true et false. Code : C# bool estVrai = true; if (estVrai) Console.WriteLine("C'est vrai !"); else Console.WriteLine("C'est faux !");

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

44/381

Il est galement possible de combiner les tests grce aux oprateurs de logique conditionnelle, par exemple && qui correspond loprateur ET. Dans lexemple qui suit, nous affichons le message de bienvenue uniquement si le login est Nicolas ET que le mot de passe est test . Si lun des deux ne correspond pas, nous irons dans linstruction else. Code : C# string login = "Nicolas"; string motDePasse = "test"; if (login == "Nicolas" && motDePasse == "test") Console.WriteLine("Bienvenue Nicolas"); else Console.WriteLine("Login incorrect");

Remarquons ici que nous avons utilis le test dgalit == , ne pas confondre avec loprateur daffection = . Cest une erreur classique de dbutant.

Dautres oprateurs de logiques existent, nous avons notamment loprateur || qui correspond au OU logique : Code : C# if (civilite == "Mme" || civilite == "Mlle") Console.WriteLine("Vous tes une femme"); else Console.WriteLine("Vous tes un homme");

Lexemple parle de lui-mme ; si la civilit de la personne est Mme ou Mlle, alors nous avons faire avec une femme. A noter ici que si la premire condition du if est vraie alors la deuxime ne sera pas value. Cest un dtail ici, mais cela peut savrer important dans certaines situations dont une que nous verrons un peu plus loin. Un autre oprateur trs courant est la ngation que lon utilise avec loprateur ! . Par exemple : Code : C# bool estVrai = true; if (!estVrai) Console.WriteLine("C'est faux !"); else Console.WriteLine("C'est vrai !");

Ce test pourrait se lire ainsi : Si la ngation de la variable estVrai est vraie, alors on crira cest faux . La variable estVrai tant gale true, sa ngation vaut false. Dans cet exemple, le programme nous affichera donc linstruction correspondant au else, savoir Cest vrai ! . Rappelez-vous, nous avons dit quune instruction se finissait en gnral par un point-virgule. Comment cela se fait-il alors quil ny ait pas de point-virgule la fin du if ou du else ? Et si nous crivions lexemple prcdent de cette faon ?

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Code : C# bool estVrai = true; if (!estVrai) Console.WriteLine("C'est faux !"); else Console.WriteLine("C'est vrai !");

45/381

Ceci est tout fait valable et permet de voir o sarrte vraiment linstruction grce au point-virgule. Cependant, nous crivons en gnral ces instructions de la premire faon afin que celles-ci soient plus lisibles. V ous aurez loccasion de rencontrer dans les chapitres suivants dautres instructions qui ne se terminent pas obligatoirement par un point-virgule. Nous verrons dans le chapitre suivant comment excuter plusieurs instructions aprs une instruction conditionnelle en les groupant dans des blocs de code, dlimits par des accolades { et } .

Remarquons enfin qu'il est possible denchaner les tests de manire traiter plusieurs conditions en utilisant la combinaison else-if. Cela donne : Code : C# if (civilite == "Mme") Console.WriteLine("Vous tes une femme"); else if (civilite == "Mlle") Console.WriteLine("Vous tes une femme non marie"); else if (civilite == "M.") Console.WriteLine("Vous tes un homme"); else Console.WriteLine("Je n'ai pas pu dterminer votre civilit");

L'instruction "Switch"
Linstruction switch peut tre utilise lorsquune variable peut prendre beaucoup de valeurs. Elle permet de simplifier lcriture. Ainsi, linstruction suivante : Code : C# string civilite = "M."; if (civilite == "M.") Console.WriteLine("Bonjour monsieur"); if (civilite == "Mme") Console.WriteLine("Bonjour madame"); if (civilite == "Mlle") Console.WriteLine("Bonjour mademoiselle");

pourra scrire : Code : C# string civilite = "M."; switch (civilite) { case "M." : Console.WriteLine("Bonjour monsieur"); break; case "Mme": Console.WriteLine("Bonjour madame"); break; case "Mlle": Console.WriteLine("Bonjour mademoiselle");

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


} break;

46/381

Switch commence par valuer la variable qui lui est passe entre parenthses. Avec le mot cl case on numre les diffrents cas possible pour la variable et on excute les instructions correspondante jusquau mot cl break qui signifie que lon sort du switch. Nous pouvons galement indiquer une valeur par dfaut en utilisant le mot cl default, ainsi dans lexemple suivant tout ce qui nest pas M. ou Mme ou Mlle donnera laffichage dun Bonjour inconnu : Code : C# switch (civilite) { case "M." : Console.WriteLine("Bonjour break; case "Mme": Console.WriteLine("Bonjour break; case "Mlle": Console.WriteLine("Bonjour break; default: Console.WriteLine("Bonjour break; }

monsieur"); madame"); mademoiselle"); inconnu");

Nous pouvons galement enchainer plusieurs cas pour quils fassent la mme chose, ce qui reproduit le fonctionnement de loprateur logique OU ( || ). Par exemple, on pourra remplacer lexemple suivant : Code : C# string mois = "Janvier"; if (mois == "Mars" || mois == "Avril" || mois == "Mai") Console.WriteLine("C'est le printemps"); if (mois == "Juin" || mois == "Juillet" || mois == "Aout") Console.WriteLine("C'est l't"); if (mois == "Septembre" || mois == "Octobre" || mois == "Novembre") Console.WriteLine("C'est l'automne"); if (mois == "Decembre" || mois == "Janvier" || mois == "Fvrier") Console.WriteLine("C'est l'hiver");

par : Code : C# switch (mois) { case "Mars": case "Avril": case "Mai": Console.WriteLine("C'est le printemps"); break; case "Juin": case "Juillet": case "Aout": Console.WriteLine("C'est l't");

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


break; case "Septembre": case "Octobre": case "Novembre": Console.WriteLine("C'est l'automne"); break; case "Dcembre": case "Janvier": case "Fvrier": Console.WriteLine("C'est l'hiver"); break;

47/381

Qui allge quand mme lcriture et la rend beaucoup plus lisible.

En rsum
Les instructions conditionnelles permettent d'excuter des instructions seulement si une condition est vrifie. On utilise en gnral le rsultat d'une comparaison dans une instruction conditionnelle. Le C# possde beaucoup d'oprateurs de comparaison, comme l'oprateur d'galit ==, l'oprateur de supriorit >, d'infriorit <, etc.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

48/381

Les blocs de code et la porte dune variable


Nous avons rgulirement utilis dans le chapitre prcdent les accolades ouvrantes et fermantes : \{ et \}. Nous avons rapidement dit que ces accolades servaient crer des blocs de code. L'utilisation d'accolades implique galement une autre subtilit. V ous l'avez vu dans le titre du chapitre, il s'agit de la porte d'une variable. Regardons prsent comment cela fonctionne.

Les blocs de code


Les blocs de code permettent de grouper plusieurs instructions qui vont sexcuter dans le mme contexte. Cela peut tre le cas par exemple aprs un if, nous pourrions souhaiter effectuer plusieurs instructions. Par exemple : Code : C# decimal compteEnBanque = 300; if (compteEnBanque >= 0) { Console.WriteLine("Votre compte est crditeur"); Console.WriteLine("Voici comment ouvrir un livret "); } else { Console.WriteLine("Votre compte est dbiteur"); Console.WriteLine("Noubliez pas que les frais de dcouverts sont de "); }

Ici, nous enchanons deux Console.WriteLine en fonction du rsultat de la comparaison de compteEnBanque avec 0. Les blocs de code seront utiles ds quon voudra regrouper plusieurs instructions. Cest le cas pour les instructions conditionnelles mais nous verrons beaucoup dautres utilisations, comme le switch que nous avons vu juste au-dessus, les boucles ou les mthodes que nous allons aborder dans le chapitre suivant.

La porte dune variable


C# porte on se croirait au cours de musique En fait, la porte dune variable est la zone de code dans laquelle une variable est utilisable. Elle correspond en gnral au bloc de code dans lequel est dfinie la variable. Ainsi, le code suivant : Code : C# static void Main(string[] args) { string prenom = "Nicolas"; string civilite = "M."; if (prenom == "Nicolas") { int age = 30; Console.WriteLine("Votre age est : " + age); switch (civilite) { case "M.": Console.WriteLine("Vous tes un homme de " + age + " ans"); break; case "Mme": Console.WriteLine("Vous tes une femme de " + age + " ans"); break; }

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


} if (age >= 18) { Console.WriteLine(prenom + ", vous tes majeur"); }

49/381

est incorrect et provoquera une erreur de compilation. En effet, nous essayons daccder la variable age en dehors du bloc de code o elle est dfinie. Nous voyons que cette variable est dfinie dans le bloc qui est excut lorsque le test dgalit du prnom avec la chaine Nicolas est vrai alors que nous essayons de la comparer 18 dans un endroit o elle nexiste plus. Nous pouvons utiliser age sans aucun problme dans tout le premier if, et mme dans les sous blocs de code, comme cest le cas dans le sous bloc du switch, mais pas en dehors du bloc de code dans lequel la variable est dfinie. Ainsi, la variable prenom est accessible dans le dernier if car elle a t dfinie dans un bloc pre. V ous noterez quici, la compltion nous est utile. En effet, Visual C# express propose de nous complter le nom de la variable dans un bloc o elle est accessible. Dans un bloc o elle ne lest pas, la compltion automatique ne nous la propose pas. Comme Visual C# express est malin comme une machine, si la compltion ne propose pas ce que vous souhaitez, cest probablement que vous ny avez pas le droit. Une des explications peut tre que la porte ne vous lautorise pas. Pour corriger lexemple prcdent, il faut dclarer la variable age au mme niveau que la variable prnom.

Ok, mais alors, pourquoi on ne dclarerait pas tout au dbut une bonne fois pour toute ? Cela viterait ces erreurs non ?

Evidemment non, vous verrez quil nest pas possible de faire cela. Gnralement, lutilisation de variables accessibles de partout est une mauvaise pratique de dveloppement (cest ce quon appelle des variables globales ). Mme si on peut avoir un quivalent en C#, il faut se rappeler que plus une variable est utilise dans la plus petite porte possible, mieux elle sera utilise et plus elle sera pertinente. Je vous conseille donc dessayer de dterminer le bloc de code minimal o lutilisation de la variable est adapte.

En rsum
Un bloc de code permet de regrouper des instructions qui commencent par \{ et qui finissent par \}. Une variable dfinie l'intrieur d'un bloc de code aura pour porte ce bloc de code.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

50/381

Les mthodes
lment indispensable de tout programme informatique, une mthode regroupe un ensemble d'instructions, pouvant prendre des paramtres et pouvant renvoyer une valeur. Lors de vos dveloppements, vous allez avoir besoin de crer beaucoup de mthodes. Nous allons dcouvrir les mthodes dans ce chapitre mais nous y reviendrons petit petit tout au long de ce cours et vous aurez ainsi l'occasion d'approfondir vos connaissances. V ous pourrez trouver de temps en temps le mot fonction la place du mot mthode . Cela signifie la mme chose. C'est une relique du pass correspondant un ancien mode de dveloppement qui s'utilise de moins en moins, de mme que le terme procdure qui est encore plus vieux !

Crer une mthode


Le but de la mthode est de factoriser du code afin dviter davoir rpter sans arrt le mme code et ceci pour deux raisons essentielles : Dj parce que lhomme est un tre paresseux qui utilise son intelligence pour viter le travail inutile. Ensuite parce que si jamais il y a quelque chose corriger dans ce bout de code et sil est dupliqu plusieurs endroits, alors nous allons devoir faire une correction dans tous ces endroits. Si le code est factoris un unique endroit, nous ferons une unique correction. (Oui oui, encore la paresse mais aussi cela permet dviter doublier un bout de code dans un endroit cach). Ce souci de factorisation est connu comme le principe DRY qui est lacronyme des mots anglais Dont Repeat Yourself , ce qui veut bien sr dire : Ne vous rptez pas . Le but de ce principe est de ne jamais ( quelques exceptions prs bien sr ) avoir rcrire la mme ligne de code. Par exemple, imaginons quelques instructions qui soccupent dcrire un message de bienvenue avec le nom de lutilisateur. Le code C# pourrait tre : Code : C# Console.WriteLine("Bonjour Nicolas"); Console.WriteLine("-------" + Environment.NewLine); Console.WriteLine("\tBienvenue dans le monde merveilleux du C#");

Note : Dans linstruction Console.WriteLine que nous utilisons rgulirement, WriteLine est une mthode.

Si plus tard, on veut r-afficher le message de bienvenue, il faudra rcrire ces 4 lignes de codes. Sauf si nous utilisons une mthode : Code : C# static void AffichageBienvenue() { Console.WriteLine("Bonjour Nicolas"); Console.WriteLine("-------" + Environment.NewLine); Console.WriteLine("\tBienvenue dans le monde merveilleux du C#"); }

Dans lexemple prcdent, je dfinis une mthode qui sappelle AffichageBienvenue. Linstruction : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


static void AffichageBienvenue()

51/381

est ce quon appelle la signature de la mthode. Elle nous renseigne sur les paramtres de la mthode et sur ce quelle va renvoyer. Le mot cl void signifie que la mthode ne renvoie rien. Les parenthses vides la fin de la signature indiquent que la mthode na pas de paramtres. Cest la forme de la mthode la plus simple possible.

Le mot cl static ne nous intresse pas pour linstant, mais sachez quil sert indiquer que la mthode est toujours disponible et prte tre utilise. Dans ce contexte, il est obligatoire. Nous y reviendrons. En-dessous de la signature de la mthode, nous retrouvons les accolades. Elles permettent de dlimiter la mthode. Le bloc de code ainsi form constitue ce quon appelle le corps de la mthode . En rsum, pour dclarer une mthode, nous aurons : Code : Autre Signature de la mthode { Bloc de code de la mthode }

Nous pouvons dsormais appeler (c'est--dire : excuter) cette mthode dans notre programme grce son nom. Par exemple, ici je lappelle trs facilement 2 fois de suite : Code : C# static void Main(string[] args) { AffichageBienvenue(); AffichageBienvenue(); } static void AffichageBienvenue() { Console.WriteLine("Bonjour Nicolas"); Console.WriteLine("-------" + Environment.NewLine); Console.WriteLine("\tBienvenue dans le monde merveilleux du C#"); }

Et tout a, sans efforts ! Cest quand mme plus simple et plus clair, non ?

La mthode spciale Main()


La signature de la mthode que lon vient de crer ne vous rappelle rien ? Mais si, lautre bloc au-dessus de notre mthode, qui ressemble lui aussi une mthode. Il sagit dune mthode spciale, la mthode Main().

Elle a t gnre par Visual C# express lorsque nous avons cr le projet Console.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

52/381

Cette mthode est en fait le point dentre de lapplication, cest--dire que quand le CLR tente dexcuter notre application, il recherche cette mthode afin de pouvoir commencer excuter des instructions partir delle. Sil ne la trouve pas, alors, il ne pourra pas excuter notre application. Cest pour cela quil est important que cette mthode soit accessible de partout ; rappelezvous, cest grce au mot cl static que nous aurons loccasion dtudier plus en dtail ultrieurement. Visual C# express nous garde bien de cette erreur. En effet, si vous supprimez cette mthode (ou que vous enlevez le mot cl static) et que vous tentez de compiler notre application, vous aurez le message derreur suivant : Citation : Compilateur Erreur 1 Le programme 'C:\Users\Nico\Documents\Visual Studio 2010\Projects\C#\MaPremiereApplication\MaPremiereApplication\obj\x86\Release\MaPremiereApplication.exe' ne contient pas une mthode 'Main' statique approprie pour un point d'entre Le message derreur est clair. Il a besoin dune mthode Main() pour dmarrer. V pour cette mthode spciale Main(). Elle est indispensable dans tout programme excutable et cest par l que le oil programme dmarre. Les lecteurs attentifs auront remarqu que cette mthode possde des choses dans la signature, entre les parenthses Des paramtres ! Dcouvrons-les dans le prochain chapitre

Paramtres dune mthode


Super, nous savons crer des mthodes. Nous allons pouvoir crer une mthode qui permet de souhaiter la bienvenue la personne qui vient de se connecter notre application par exemple. Si cest Nicolas qui vient de se connecter, nous allons pouvoir appeler la mthode AffichageBienvenueNicolas(). Si cest Jrmie, nous appellerons la mthode AffichageBienvenueJeremie(), etc Code : C# static void AffichageBienvenueNicolas() { Console.WriteLine("Bonjour Nicolas"); Console.WriteLine("-------" + Environment.NewLine); Console.WriteLine("\tBienvenue dans le monde merveilleux du C#"); } static void AffichageBienvenueJeremie() { Console.WriteLine("Bonjour Jrmie"); Console.WriteLine("-------" + Environment.NewLine); Console.WriteLine("\tBienvenue dans le monde merveilleux du C#"); }

Bof finalement, ce nest pas si super que a en fait. Alors que nous venions juste dvoquer le principe DRY nous nous , retrouvons avec deux mthodes quasiment identiques qui ne diffrent que dune toute petite chose. Cest l quinterviennent les paramtres de mthodes. Nous lavons voqu au paragraphe prcdent, il est possible de passer des paramtres une mthode. Ainsi, nous pourrons utiliser les valeurs de ces paramtres dans le corps de nos mthodes, les mthodes en deviendront dautant plus gnriques. Dans notre exemple daffichage de message de bienvenue, il est vident que le nom de lutilisateur sera un paramtre de la mthode. Les paramtres scrivent lintrieur des parenthses qui suivent le nom de la mthode. Nous devons indiquer le type du paramtre ainsi que le nom de la variable qui le reprsentera au sein de la mthode. Il est possible de passer plusieurs paramtres une mthode, on les sparera avec une virgule. Par exemple : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


static void DireBonjour(string prenom, int age) { Console.WriteLine("Bonjour " + prenom); Console.WriteLine("Vous avez " + age + " ans"); }

53/381

Ici, la mthode DireBonjour prend en paramtres une chaine de caractres prenom et un entier age. La mthode affiche Bonjour ainsi que le contenu de la variable prenom. De mme, juste en dessous, elle affiche lge qui a t pass en paramtres. Nous pourrons appeler cette mthode de cette faon, depuis la mthode Main() : Code : C# static void Main(string[] args) { DireBonjour("Nicolas", 30); DireBonjour("Jrmie", 20); }

Et nous aurons :

Bien sr, il est obligatoire de fournir en paramtres dune mthode une variable du mme type que le paramtre. Sinon, le compilateur sera incapable de mettre la donne qui a t passe dans le paramtre. Dailleurs, si vous ne fournissez pas le bon paramtre, vous aurez droit une erreur de compilation. Par exemple, si vous appelez la mthode avec les paramtres suivants : Code : C# DireBonjour(10, 10);

V ous aurez lerreur de compilation suivante :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Citation : Compilateur impossible de convertir de 'int' en 'string'

54/381

Il est videmment possible de passer des variables une mthode, cela fonctionne de la mme faon : Code : C# string prenom = "Nicolas"; DireBonjour(prenom, 30);

Nous allons revenir plus en dtail sur ce quil se passe exactement ici dans le chapitre sur le mode de passage des paramtres. V ous voyez, cela ressemble beaucoup ce que nous avons dj fait avec la mthode Console.WriteLine(). Facile, non ?

La mthode Console.WriteLine fait partie de la bibliothque du framework .NET et est utilise pour crire des chaines de caractres, des nombres ou plein dautres choses sur la console. Le framework .NET contient normment de mthodes utilitaires de toutes sortes, nous y reviendrons. V ous aurez peut-tre remarqu un dtail, nous avons prfix toutes nos mthodes du mot cl static. Jai dit que ctait obligatoire dans notre contexte, pour tre plus prcis, cest parce que la mthode Main() est statique que nous sommes obligs de crer des mthodes statiques. On a dit que la mthode Main() tait obligatoirement statique parce quelle devait tre accessible de partout afin que le CLR puisse trouver le point dentre de notre programme. Or, une mthode statique ne peut appeler que des mthodes statiques, cest pour cela que nous sommes obligs (pour linstant) de prfixer nos mthodes par le mot cl static. Nous dcrirons ce que recouvre exactement le mot cl static dans la partie suivante.

Retour dune mthode

Une mthode peut aussi renvoyer une valeur, par exemple un calcul. Cest souvent dailleurs son utilit premire. On pourrait imaginer par exemple une mthode qui calcule la longueur de lhypotnuse partir des 2 cts dun triangle. Sachant que a + b = c, nous pouvons imaginer une mthode qui prend en paramtres la longueur des 2 cots, fait la somme de leur carrs et renvoie la racine carr du rsultat. Cest ce que fait la mthode suivante : Code : C# static double LongueurHypotenuse(double a, double b) { double sommeDesCarres = a * a + b * b; double resultat = Math.Sqrt(sommeDesCarres); return resultat; }

Continuons ignorer le mot cl static. V ous aurez remarqu que la signature de la mthode commence par le mot cl double, qui indique que la mthode va nous renvoyer une valeur du type double. Comme on la vu, double a et double b sont deux paramtres de la mthode et sont du type double. La mthode Math.Sqrt est une mthode du framework .NET, au mme titre que la mthode Console.WriteLine, qui permet de renvoyer la racine carre dun nombre. Elle prend en paramtre un double et nous retourne une valeur de type double galement qui correspond la racine carre du paramtre. Cest tout naturellement que nous stockons ce rsultat dans une variable grce loprateur daffectation = . la fin de la mthode, le mot cl return indique que la mthode renvoie la valeur la mthode qui la appele. Ici, nous renvoyons le rsultat. Cette mthode pourra sutiliser ainsi : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


static void Main(string[] args) { double valeur = LongueurHypotenuse(1, 3); Console.WriteLine(valeur); valeur = LongueurHypotenuse(10, 10); Console.WriteLine(valeur); }

55/381

Comme prcdemment, nous utilisons une variable pour stocker le rsultat de lexcution de la mthode. Ce qui produira comme rsultat :

noter quil est galement possible de se passer dune variable intermdiaire pour stocker le rsultat. Ainsi, nous pourrons par exemple faire : Code : C# Console.WriteLine("Le rsultat est : " + LongueurHypotenuse(1, 3));

Avec cette criture le rsultat renvoy par la mthode LongueurHypotenuse est directement concatn la chaine "Le rsultat est : " et est pass en paramtre la mthode Console.WriteLine. Remarquez quon a fait lopration a*a pour mettre a au carr. On aurait galement pu faire Math.Pow(a, 2) qui permet de faire la mme chose, la diffrence est que Pow permet de mettre la puissance que lon souhaite. Ainsi, Math.Pow(a, 3) permet de mettre a au cube. Il faut savoir que le mot cl return peut apparaitre nimporte quel endroit de la mthode. Il interrompt alors lexcution de celle-ci et renvoie la valeur passe. Ce mot-cl est obligatoire, sans cela la mthode ne compilera pas. Il est galement primordial que tous les chemins possibles dune mthode renvoient quelque chose. Les chemins sont dtermins par les instructions conditionnelles que nous avons vues prcdemment. Ainsi, lexemple suivant est correct : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

56/381

static string Conjugaison(string genre) { if (genre == "homme") return ""; else return "e"; }

car peu importe la valeur de la variable genre , la mthode renverra une chaine. Alors que celui-ci : Code : C# static string Conjugaison(string genre) { if (genre == "homme") return ""; else { if (genre == "femme") return "e"; } }

est incorrect. En effet, que renvoie la mthode si la variable genre contient autre chose que homme ou femme ? En gnral, Visual C# express nous indiquera quil dtecte un problme avec une erreur de compilation. Nous pourrons corriger ceci avec par exemple : Code : C# static string Conjugaison(string genre) { if (genre == "homme") return ""; else { if (genre == "femme") return "e"; } return ""; }

noter que "" correspond une chaine vide et peut galement scrire : string.Empty.

Nous avons vu dans le chapitre prcdent quil tait possible de crer des mthodes qui ne retournent rien. Dans ce cas, on peut utiliser le mot cl return sans valeur qui le suit pour stopper lexcution de la mthode. Par exemple : Code : C# static void Bonjour(string prenom) {

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


if (prenom == "inconnu") return; Console.WriteLine("Bonjour " + prenom);

57/381

Ainsi, si la variable prenom vaut inconnu , alors nous quittons la mthode Bonjour et linstruction Console.WriteLine ne sera pas excute.

En rsum

Une mthode regroupe un ensemble dinstructions pouvant prendre des paramtres et pouvant renvoyer une valeur. Les paramtres d'une mthode doivent tre utiliss avec le bon type. Une mthode qui ne renvoie rien est prfixe du mot-cl void. Le point d'entre d'un programme est la mthode statique Main(). Le mot-cl return permet de renvoyer une valeur du type de retour de la mthode, l'appelant de cette mthode.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

58/381

Tableaux, listes et numrations


Dans les chapitres prcdents, nous avons pu utiliser les types de base du framework .NET, comme int, string, double, etc. Nous allons dcouvrir ici d'autres types qui vont s'avrer trs utiles dans la construction de nos applications informatiques. Une fois bien matriss, vous ne pourrez plus vous en passer !

Les tableaux
V le premier nouveau type que nous allons tudier, le type tableau . En dclarant une variable de type tableau, nous allons oici en fait utiliser une variable qui contient une suite de variables du mme type. Prenons cet exemple : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };

Nous dfinissons ici un tableau de chaine de caractres qui contient 7 chaines de caractres, savoir les jours de la semaine. Ne faites pas trop attention loprateur new pour linstant, nous y reviendrons plus tard ; il permet simplement de crer le tableau. Les crochets [] qui suivent le nom du type permettent de signaler au compilateur que nous souhaitons utiliser un tableau de ce type-l, ici le type string. Un tableau, cest un peu comme une armoire dans laquelle on range des variables. Chaque variable est pose sur une tagre. Pour accder la variable qui est pose sur une tagre, on utilise le nom de larmoire et on indique lindice de ltagre o est stocke la variable, en utilisant des crochets [] : Code : C# Console.WriteLine(jours[3]); // affiche Jeudi Console.WriteLine(jours[0]); // affiche Lundi Console.WriteLine(jours[10]); // provoque une erreur d'excution car l'indice n'existe pas

Attention, le premier lment du tableau se situe lindice 0 et le dernier se situe lindice taille du tableau 1 , c'est--dire 6 dans notre exemple. Si on tente daccder un indice qui nexiste pas, lapplication lvera une erreur. Sans anticiper sur le chapitre sur les boucles, il est possible de parcourir lensemble dun tableau avec linstruction suivante : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; for (int i = 0; i < jours.Length; i++) { Console.WriteLine(jours[i]); }

Nous y reviendrons plus tard mais pour comprendre, ici nous parcourons les lments de 0 taille-1 et nous affichons llment du tableau correspondant lindice en cours. Ce qui nous donne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

59/381

Revenons prsent sur la dclaration du tableau : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };

Cette criture permet de crer un tableau qui contient 7 lments et daffecter une valeur chaque lment du tableau. Il sagit en fait ici dune criture simplifie. Cette criture est quivalente celle-ci : Code : C# string[] jours[0] jours[1] jours[2] jours[3] jours[4] jours[5] jours[6] jours = new string[7]; = "Lundi"; = "Mardi"; = "Mercredi"; = "Jeudi"; = "Vendredi"; = "Samedi"; = "Dimanche";

qui est beaucoup plus verbeuse, mais dun autre ct, plus explicite. La premire instruction cre un tableau qui peut contenir 7 lments. 7 indique la taille du tableau, elle ne peut pas changer. Chaque instruction suivante affecte une valeur un indice du tableau. Rappelez-vous, un tableau commence lindice 0 et va jusqu lindice taille 1. Il est possible facilement de faire des oprations sur un tableau, comme un tri. On pourra utiliser la mthode Array.Sort(). Par exemple : Code : C# Array.Sort(jours);

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

60/381

Avec cette instruction, le tableau sera class par ordre alphabtique. V ous aurez loccasion de voir dautres mthodes dans des chapitres ultrieurs. Ainsi, le code suivant : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; Array.Sort(jours); for (int i = 0; i < jours.Length; i++) { Console.WriteLine(jours[i]); }

produira :

Ce qui est trs inutile

Le tableau jours est ce que lon appelle un tableau une dimension. Il est galement possible de crer des tableaux N dimensions, il est cependant assez rare de dpasser 2 dimensions. Cela est utile lorsque lon manipule des matrices. Nous n'tudierons pas les tableaux plus d'une dimension dans ce tutoriel car ils risquent de vraiment peu vous servir dans vos premires applications. Par contre, le type suivant vous servira abondamment.

Les listes
Un autre type que nous allons utiliser foison est la liste. Nous allons voir comment ce type fonctionne mais sans en faire une tude exhaustive car elle pourrait tre bien longue et ennuyeuse. Regardons cet exemple : Code : C# List<int> chiffres = new List<int>(); chiffres.Add(8); // chiffres contient chiffres.Add(9); // chiffres contient chiffres.Add(4); // chiffres contient // cration de la liste 8 8, 9 8, 9, 4

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


chiffres.RemoveAt(1); // chiffres contient 8, 4 foreach (int chiffre in chiffres) { Console.WriteLine(chiffre); }

61/381

La premire ligne permet de crer la liste. Nous reviendrons sur cette instruction un peu plus bas dans le chapitre. Il sagit dune liste dentiers. Nous ajoutons des entiers la liste grce la mthode Add(). Nous ajoutons en loccurrence les entiers 8, 9 et 4. La mthode RemoveAt() permet de supprimer un lment en utilisant son indice, ici nous supprimons le deuxime entier, cest-dire 9. Comme les tableaux, le premier lment de la liste commence lindice 0.

Aprs cette instruction, la liste contient les entiers 8 et 4. Enfin, nous parcourons les lments de la liste grce linstruction foreach. Nous y reviendrons en dtail lors du chapitre sur les boucles. Pour linstant, nous avons juste besoin de comprendre que nous affichons tous les lments de la liste. Ce qui donne :

Les lecteurs assidus auront remarqus que la construction de la liste est un peu particulire. Passons sur le mot cl new qui permet de crer la liste, nous y reviendrons plus en dtail dans un prochain chapitre. Par contre, on observe lutilisation de chevrons <> pour indiquer le type de la liste. Pour avoir une liste dentier, il suffit dindiquer le type int lintrieur des chevrons. Ainsi, il ne sera pas possible dajouter autre chose quun entier dans cette liste. Par exemple, linstruction suivante provoque une erreur de compilation : Code : C# List<int> chiffres = new List<int>(); // cration de la liste chiffres.Add("chaine"); // ne compile pas

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Evidemment, on ne peut pas ajouter des choux une liste de carottes !

62/381

De la mme faon, si lon souhaite crer une liste de chaine de caractres, nous pourrons utiliser le type string lintrieur des chevrons : Code : C# List<string> chaines = new List<string>(); // cration de la liste chaines.Add("chaine"); // compilation OK chaines.Add(1); // compilation KO, on ne peut pas ajouter un entier dans une liste de chaines de caractres

Les listes possdent des mthodes bien pratiques qui permettent toutes sortes doprations sur la liste. Par exemple, la mthode IndexOf() permet de rechercher un lment dans la liste et de renvoyer son indice. Code : C# List<string> jours = new List<string>(); jours.Add("Lundi"); jours.Add("Mardi"); jours.Add("Mercredi"); jours.Add("Jeudi"); jours.Add("Vendredi"); jours.Add("Samedi"); jours.Add("Dimanche"); int indice = jours.IndexOf("Mercredi"); // indice vaut 2

Nous aurons loccasion de voir dautres utilisations de mthodes de la liste dans les chapitres suivants. La liste que nous venons de voir (List<>) est en fait ce que lon appelle un type gnrique. Nous nallons pas rentrer dans le dtail de ce quest un type gnrique pour linstant, mais il faut juste savoir quun type gnrique permet dtre spcialis par un type concret. Pour notre liste, cette gnricit permet dindiquer de quel type est la liste, une liste dentiers ou une liste de chaines de caractres, etc Ne vous inquitez pas si tout ceci nest pas parfaitement clair, nous reviendrons plus en dtail sur les gnriques dans un chapitre ultrieur. Le but ici est de commencer se familiariser avec le type List<> que nous utiliserons rgulirement et les exemples que nous verrons permettront dapprhender les subtilits de ce type. noter quil existe galement une criture simplifie des listes. En effet, il est possible de remplacer : Code : C# List<string> jours = new List<string>(); jours.Add("Lundi"); jours.Add("Mardi"); jours.Add("Mercredi"); jours.Add("Jeudi"); jours.Add("Vendredi"); jours.Add("Samedi"); jours.Add("Dimanche");

par Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


un peu comme pour les tableaux.

63/381

Liste ou tableau ?
V ous aurez remarqu que les deux types, tableau et liste, se ressemblent beaucoup. Essayons de voir ce qui les diffrencie afin de savoir quel type choisir entre les deux. En fait, une des grosses diffrences est que le tableau peut tre multidimensionnel. Cest un point important mais dans le cadre de vos premires applications, il est relativement rare davoir sen servir. Ils serviront globalement plus souvent dans le dveloppement de jeux ou lorsque lon souhaite faire des calculs 3D. Par contre, le plus important pour nous est que le type tableau est de taille fixe alors que la liste est de taille variable. On peut ajouter sans problmes un nouvel lment grce la mthode Add(). De mme, on peut supprimer des lments avec les mthodes Remove alors quavec un tableau, on peut seulement remplacer les valeurs existantes et il nest pas possible daugmenter sa capacit. Globalement, vous verrez que dans vos applications, vous utiliserez plutt les listes pour par exemple afficher une liste de produits, une liste de clients, etc Gardez quand mme dans un coin de lesprit les tableaux, ils pourront vous aider dans des situations prcises.

Les numrations
Un type particulier que nous allons galement utiliser est lnumration. Cela correspond comme son nom lindique une numration de valeur. Par exemple, il pourrait tre trs facile de reprsenter les jours de la semaine dans une numration plutt que dans un tableau. On dfinit lnumration de cette faon, grce au mot cl enum : Code : C# enum Jours { Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche }

noter quon ne peut pas dfinir cette numration nimporte o, pour linstant, contentons-nous de la dfinir en dehors de la mthode Main(). Pour tre tout fait prcis, une numration est un type dont toutes les valeurs dfinies sont des entiers. La premire vaut 0, et chaque valeur suivante prend la valeur prcdente augmente de 1. C'est--dire que Lundi vaut 0, Mardi vaut 1, etc Il est possible de forcer des valeurs toutes ou certaines valeurs de lnumration, les valeurs non forces prendront la valeur prcdente augmente de 1 : Code : C# enum Jours { Lundi = 5, // lundi vaut 5 Mardi, // mardi vaut 6 Mercredi = 9, // mercredi vaut 9 Jeudi = 10, // jeudi vaut 10 Vendredi, // vendredi vaut 11 Samedi, // samedi vaut 12 Dimanche = 20 // dimanche vaut 20 }

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

64/381

Mais, part pour enregistrer une valeur dans une base de donnes, il est rare de manipuler les numrations comme des entiers car le but de lnumration est justement davoir une liste exhaustive et fixe de valeurs constantes. Le code sen trouve plus clair, plus simple et plus lisible. Le fait de dfinir une telle numration revient en fait enrichir les types que nous avons notre disposition, comme les entiers ou les chaines de caractres (int ou string). Ce nouveau type sappelle Jours . Nous pourrons dfinir une variable du type Jours de la mme faon quavec un autre type : Code : C# Jours jourDeLaSemaine;

La seule diffrence cest que les valeurs quil est possible daffecter notre variable sont figes et font partie des valeurs dfinies dans lnumration. Pour pouvoir accder un lment de lnumration, il faudra utiliser le nom de lnumration suivi de loprateur point . suivi encore de la valeur de lnumration choisie. Par exemple : Code : C# Jours lundi = Jours.Lundi; Console.WriteLine(lundi);

soit dans notre programme : Code : C# class Program { enum Jours { Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche } static void Main(string[] args) { Jours lundi = Jours.Lundi; Console.WriteLine(lundi); }

Ce qui nous donne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

65/381

Nous pourrons galement nous servir des numrations pour faire des tests de comparaisons, comme par exemple : Code : C# if (jourDeLaSemaine == Jours.Dimanche || jourDeLaSemaine == Jours.Samedi) { Console.WriteLine("Bon week-end"); }

Sachez que le framework .NET utilise beaucoup les numrations. Il est important de savoir les manipuler. V ous aurez peut-tre remarqu que lorsqu'on affiche la valeur d'une numration, la console nous affiche le nom de l'numration et non pas sa valeur entire. a peut paratre trange, mais c'est parce que le C# fait un traitement particulier dans le cadre d'une numration l'affichage.

En rsum
Un tableau est un type volu pouvant contenir une squence d'autres types, comme un tableau d'entiers ou un tableau de chanes de caractres. Une liste est un type complexe un peu plus souple que le tableau permettant d'avoir une liste de n'importe quel type. Une numration s'utilise lorsque l'on veut crer un type possdant plusieurs valeurs fixes, comme les jours de la semaine.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

66/381

Utiliser le framework .NET


Comme on l'a dj voqu, le framework .NET est une norme bote outils qui contient beaucoup de mthodes permettant de construire toutes sortes d'applications. Nous allons avoir besoin rgulirement d'utiliser les lments du framework .NET pour raliser nos applications. Il est donc grand temps d'apprendre savoir le manipuler ! Rentrons tout de suite dans le vif du sujet.

Linstruction using
Nous allons sans arrt solliciter la puissance du framework .NET. Par exemple, nous pouvons lui demander de nous donner la date courante. Pour ce faire, on utilisera linstruction : Code : C# Console.WriteLine(DateTime.Now);

Ce quil se passe ici, cest que nous demandons notre application laffichage de la proprit Now de lobjet DateTime. Nous allons revenir en dtail sur ce que sont des proprits et des objets, considrez pour linstant quils correspondent simplement une instruction qui nous fournit la date du moment. Ce qui donne :

En fait, pour accder la date courante, on devrait normalement crire : Code : C# System.Console.WriteLine(System.DateTime.Now);

Car les objets DateTime et Console se situent dans lespace de nom System . Un espace de nom (en anglais namespace) correspond un endroit o lon range des mthodes et des objets. Il est caractris

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


par des mots spars par des points (.).

67/381

Cest un peu comme des rpertoires, nous pouvons dire que le fichier DateTime est rang dans le rpertoire System et quand nous souhaitons y accder nous devons fournir lemplacement complet du fichier, savoir System.DateTime. Cependant, plutt que dcrire le chemin complet chaque fois, il est possible de dire : ok, maintenant, chaque fois que je vais avoir besoin daccder une fonctionnalit, va la chercher dans lespace de nom System . Si elle sy trouve, utilise la . Cest ce quil se passe grce linstruction Code : C# using System;

qui a t gnre par Visual C# express au dbut du fichier. Elle indique au compilateur que nous allons utiliser (using) le namespace System dans notre page. Ainsi, il nest plus obligatoire de prfixer laccs DateTime par System. . Cest une espce de raccourci. Pour conserver lanalogie avec les rpertoires et les fichiers, on peut dire que nous avons ajout le rpertoire System dans le path. Pour rsumer, linstruction : Code : C# System.Console.WriteLine(System.DateTime.Now);

est quivalente aux deux instructions : Code : C# using System;

et Code : C# Console.WriteLine(DateTime.Now);

Sachant quelles ne scrivent pas cte cte. En gnral, on met linstruction using en entte du fichier .cs, comme ce qua fait Visual C# express lorsquil a gnr le fichier. Lautre instruction tant positionner lendroit adquat o nous souhaitons quelle soit excute. Si le using System est absent, la compltion automatique de Visual C# express ne vous proposera pas le mot DateTime . Cest un bon moyen de se rendre compte quil manque la dclaration de lutilisation de lespace de nom.

noter que dans ce cas-l, si Visual C# express reconnait linstruction mais que lespace de nom nest pas inclus, il le propose en soulignant le dbut du mot DateTime dun petit trait bleu et blanc.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

68/381

Un clic droit sur le mot permettra douvrir un menu droulant, de choisir Rsoudre et dimporter le using correspondant automatiquement.

La bibliothque de classes .NET


V ous aurez loccasion de dcouvrir que le framework .NET fourmille despace de noms contenant plein de mthodes de toutes sortes permettant de faire un peu tout et nimporte quoi. Une vraie caverne dali-baba. Parmi les nombreuses fonctionnalits du framework .NET, nous avons une mthode qui nous permet de rcuprer lutilisateur courant (au sens utilisateur windows ), on pourra par exemple utiliser linstruction suivante : Code : C# System.Console.WriteLine(System.Environment.UserName);

Qui nous affichera :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

69/381

Ou, comme vous le savez dsormais, on pourra utiliser conjointement : Code : C# using System;

et Code : C# Console.WriteLine(Environment.UserName);

Pour produire le mme rsultat. Petit petit vous allez retenir beaucoup dinstructions et despaces de nom du framework .NET mais il est inimaginable de tout retenir. Il existe une documentation rpertoriant tout ce qui compose le framework .NET, cest ce quon appelle la MSDN library. Elle est accessible cette adresse : http://msdn.microsoft.com/fr-fr/library/. Par exemple, la documentation de la proprit que nous venons dutiliser est consultable cette adresse. Nous avons dsign la caverne dali-baba par le mot framework .NET . Pour tre plus prcis, la dsignation exacte de cette caverne est : la bibliothque de classe .NET . Le mot framework .NET est en gnral utilis par abus de langage (et vous avez remarqu que jai moi-mme abus du langage !) et reprsente galement cette bibliothque de classe. Nous reviendrons plus tard sur ce quest exactement une classe, pour linstant, vous pouvez voir a comme des composants ; une bibliothque de composants.

Rfrencer une assembly


Ca y est, nous savons accder au framework .NET. Mais dailleurs, comment se fait-il que nous puissions accder aux mthodes du framework .NET sans nous poser de question ? Il est magique ce framework ? O se trouve le code qui permet de rcuprer la date du jour ? Judicieuse question. Si on y rflchit, il doit falloir beaucoup de code pour renvoyer la date du jour ! Dj, il faut aller la lire dans lhorloge systme, il faut peut-tre ladapter au fuseau horaire, la formater dune faon particulire en fonction de la langue, etc. Tout a est dj fait, heureusement, dans la bibliothque de mthodes du framework .NET.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

70/381

Alors, o est-elle cette bibliothque ? Et le reste ?

Dans des assemblys bien sr. Comme on a vu, les assemblys possdent des fragments de code compils en langage intermdiaire. Sils sont rutilisables, ils se trouvent dans des fichiers dont lextension est .dll. Le framework .NET est compos dune multitude dassemblys qui sont installs sur votre systme dexploitation, dans le GAC (global assembly cache) qui est un endroit o sont stockes ces assemblys afin de les rendre accessible depuis nos programmes. Pour pouvoir utiliser ces assemblys dans notre programme, nous devons indiquer que nous voulons les utiliser. Pour a, il faut les rfrencer dans le projet. Si lon dplie les rfrences dans notre explorateur de solutions, nous pouvons voir que nous avons dj pas mal de rfrences qui ont t ajoutes par Visual C# express :

Ce sont des assemblys qui sont trs souvent utilises, cest pour a que Visual C# express nous les a automatiquement rfrences. Toujours ce souci de nous simplifier le travail, quil est sympa ! Prenons par exemple la rfrence System.Xml. Son nom nous suggre que dedans est runi tout ce quil nous faut pour manipuler le XML. Commenons taper System.Xml., la compltion automatique nous propose plusieurs choses.

On ne sait pas du tout quoi elle sert, mais dclarons par exemple une variable de lnumration ConformanceLevel : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


System.Xml.ConformanceLevel level;

71/381

et compilons. Pas derreur de compilation. Si vous supprimez la rfrence System.Xml. (bouton droit, Supprimer),

et que vous compilez nouveau, vous pouvez voir que ConformanceLevel est dsormais soulign en rouge, signe quil y a un problme.

Par ailleurs, la compilation provoque lerreur suivante : Citation : Compilateur Le type ou le nom d'espace de noms 'ConformanceLevel' n'existe pas dans l'espace de noms 'System.Xml' (une rfrence d'assembly est-elle manquante ?)

Loin dtre bte, Visual C# express nous affiche un message derreur plutt explicite. En effet, cette numration est introuvable car elle est dfinie dans une assembly qui nest pas rfrence. Cest comme si on nous demandait de prendre le marteau pour enfoncer un clou, mais que le marteau nest pas cot de nous, mais au garage bien rang ! Il faut donc rfrencer le marteau afin de pouvoir lutiliser. Pour ce faire, faisons un clic sur Rfrences et ajoutons une rfrence.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

72/381

Ici, nous avons plusieurs onglets (selon la version de Visual Studio que vous possdez, vous aurez peut-tre une prsentation lgrement diffrente).

Chaque onglet permet dajouter une rfrence une assemblys. Longlet .NET permet de rfrencer une assembly prsente dans le GAC, cest ici que nous viendrons chercher les assemblys du framework .NET Longlet COM permet de rfrencer une dll COM. V ous ne savez pas ce quest COM ? On peut dire que cest lanctre de lassembly. Techniquement, on ne rfrence pas directement une dll COM, mais Visual C# express gnre ce quon appelle un wrapper permettant dutiliser la dll COM. Un wrapper est en fait une espce de traducteur permettant dutiliser la dll COM comme si ctait une assembly. Mais ne nous attardons pas sur ce point qui ne va pas nous servir, nous qui sommes dbutants. Longlet Projets permet de rfrencer des assemblys qui se trouvent dans notre solution. Dans la mesure o notre solution ne contient quun seul projet, longlet sera vide. Nous verrons plus tard comment utiliser cet onglet lorsque nous ajouterons des assemblys nos solutions. Longlet Parcourir va permettre de rfrencer une assembly depuis un emplacement sur le disque dur. Cela peut-tre une assembly tierce fournie par un collgue, ou par un revendeur, etc Enfin, longlet Rcent, comme son nom le suggre, permet de rfrencer des assemblys rcemment rfrences. Retournons nos moutons, repartons sur longlet .NET et recherchons lassembly que nous avons supprime, savoir System.Xml.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

73/381

Une fois trouve, appuyez sur OK. Maintenant que la rfrence est ajoute, nous pouvons nouveau utiliser cette numration Ouf ! Je ne comprends pas, jai supprim toutes les rfrences, mais jarrive quand mme utiliser la date, le nom de lutilisateur ou la mthode Console.WriteLine. Si jai bien compris, je ne devrais pas pouvoir utiliser des mthodes dont les assemblys ne sont pas rfrences Cest normal ?

Eh oui, il existe une assembly qui napparait pas dans les rfrences et qui contient tout le cur du framework .NET. Cette assembly doit obligatoirement tre rfrence, il sagit de mscorlib.dll. Comme elle est obligatoire, elle est rfrence par dfaut ds que lon cre un projet.

Dautres exemples
Il arrivera souvent que vous ayez besoin dune fonctionnalit trouve dans la documentation ou sur internet et quil faille ajouter une rfrence. Ce sera peut-tre une rfrence au framework .NET, des bibliothques tierces ou vous. Nous verrons plus loin comment crer nos propres bibliothques. Dans la documentation MSDN, il est toujours indiqu quelle assembly il faut rfrencer pour utiliser une fonctionnalit. Prenons par exemple la proprit DateTime.Now, la documentation nous dit : Citation : MSDN Espace de noms : System Assembly : mscorlib (dans mscorlib.dll)

Cela veut donc dire quon utilise la date du jour en utilisant lassembly obligatoire mscorlib et la fonctionnalit se trouve dans lespace de nom System , comme dj vu.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

74/381

Il ny a donc rien faire pour pouvoir utiliser DateTime.Now. En imaginant que nous ayons besoin de faire un programme qui utilise des nombres complexes, vous allez surement avoir besoin du type Complex, trouv dans la documentation. Pour lutiliser, comme indiqu, il va falloir rfrencer lassembly System.Numerics.dll. Rien de plus simple, rptons la procdure pour rfrencer une assembly et allons trouver System.Numerics.dll :

Ensuite, nous pourrons utiliser par exemple le code suivant : Code : C# Complex c = Complex.One; Console.WriteLine(c); Console.WriteLine("Partie relle : " + c.Real); Console.WriteLine("Partie imaginaire : " + c.Imaginary); Console.WriteLine(Complex.Conjugate(Complex.FromPolarCoordinates(1.0, 45 * Math.PI / 180)));

Sachant quil aura bien sr fallu rajouter le : Code : C# using System.Numerics;

permettant davoir viter de prfixer Complex par System.Numerics. Mais a, vous aviez trouv tout seul, nest-ce pas ? Ce qui nous donnera :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

75/381

En rsum
Le framework .NET est un ensemble d'assemblys qu'il faut rfrencer dans son projet afin d'avoir accs leurs fonctionnalits. On utilise le mot-cl using pour inclure un espace de nom comme raccourci dans son programme, ce qui permet de ne pas avoir prfixer les types de leurs espaces de noms complets.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

76/381

TP : Bonjour c'est le week-end ...


Bienvenue dans ce premier TP ! V ous avez pu dcouvrir dans les chapitres prcdents les premires bases du langage C# permettant la construction d'applications. Il est grand temps de mettre en pratique ce que nous avons appris. C'est ici l'occasion pour vous de tester vos connaissances et de valider ce que vous appris en ralisant cet exercice.

Instructions pour raliser le TP


Le but est de crer une petite application qui affiche un message diffrent en fonction du nom de lutilisateur et du moment de la journe : Bonjour XXX pour la tranche horaire 9h <-> 18h, les lundi, mardi, mercredi, jeudi et vendredi Bonsoir XXX pour la tranche horaire 18h <-> 9h, les lundi, mardi, mercredi, jeudi Bon week-end XXX pour la tranche horaire vendredi 18h <-> lundi 9h

Peut-tre cela vous parait simple, dans ce cas, foncez et ralisez cette premire application tout seul Sinon, dcortiquons un peu lnonc de ce TP pour viter dtre perdu.

Pour raliser ce premier TP, vous allez avoir besoin de plusieurs choses. Dans un premier temps, il faut afficher le nom de lutilisateur, cest une chose que nous avons dj faite en allant puiser dans les fonctionnalits du framework .NET. V ous aurez besoin galement de rcuprer lheure courante pour la comparer aux tranches horaires souhaites. V ous avez dj vu comment rcuprer la date courante. Pour pouvoir rcuprer lheure de la date courante, il vous faudra utiliser linstruction DateTime.Now.Hour qui renvoie un entier reprsentant lheure du jour. Pour comparer lheure avec des valeurs entires il vous faudra utiliser les oprateurs de comparaisons et les instructions conditionnelles que nous avons vus prcdemment. Pour traiter le cas spcial du jour de la semaine, vous aurez besoin que le framework .NET vous indique quel jour nous sommes. Cest le rle de linstruction DateTime.Now.DayOfWeek qui est une numration indiquant le jour de la semaine. Les diffrentes valeurs sont consultables cette adresse. Pour plus de clart, nous les reprenons ici : Valeur Sunday Monday Tuesday Traduction Dimanche Lundi Mardi

Wednesday Mercredi Thursday Friday Saturday Jeudi Vendredi Samedi

Il ne restera plus qu comparer deux valeurs dnumration, comme on la vu au chapitre sur les numrations. V oil, vous avez tous les outils en main pour raliser ce premier TP. Nhsitez pas revenir sur les chapitres prcdents si vous avez un doute sur la syntaxe ou sur les instructions raliser. On ne peut pas apprendre un langage par cur du premier coup. vous de jouer !

Correction
V ous tes autoriss lire cette correction uniquement si vous vous tes arrach les cheveux sur ce TP ! Je vois qu'il vous en reste, encore un effort ! Quoique, si vous avez russi avec brio le TP, vous pourrez galement comparer votre travail au mien. Quoi quil en soit, voici la correction que je propose. Bien videmment, il peut y en avoir plusieurs, mais elle contient les

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


informations ncessaires pour la ralisation de ce TP. Premire chose faire : crer un projet de type console. Jai ensuite ajout le code suivant : Code : C# static void Main(string[] args) { if (DateTime.Now.DayOfWeek == DayOfWeek.Saturday || DateTime.Now.DayOfWeek == DayOfWeek.Sunday) { // nous sommes le week-end AfficherBonWeekEnd(); } else { // nous sommes en semaine if (DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.Hour < 9) { // nous sommes le lundi matin AfficherBonWeekEnd(); } else { if (DateTime.Now.Hour >= 9 && DateTime.Now.Hour < 18) { // nous sommes dans la journe AfficherBonjour(); } else { // nous sommes en soire if (DateTime.Now.DayOfWeek == DayOfWeek.Friday && DateTime.Now.Hour >= 18) { // nous sommes le vendredi soir AfficherBonWeekEnd(); } else { AfficherBonsoir(); } } } } } static void AfficherBonWeekEnd() { Console.WriteLine("Bon week-end " + Environment.UserName); } static void AfficherBonjour() { Console.WriteLine("Bonjour " + Environment.UserName); } static void AfficherBonsoir() { Console.WriteLine("Bonsoir " + Environment.UserName); }

77/381

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Dtaillons un peu ce code :

78/381

Au chargement du programme (mthode Main) nous faisons les comparaisons adquates. Dans un premier temps, nous testons le jour de la semaine de la date courante (DateTime.Now.DayOfWeek) et nous la comparons aux valeurs reprsentant Samedi et Dimanche. Si cest le cas, alors nous appelons une mthode qui affiche le message Bon week-end avec le nom de lutilisateur courant que nous pouvons rcuprer avec Enrivonment.UserName. Si nous ne sommes pas le week-end, alors nous testons lheure de la date courante avec DateTime.Now.Hour. Si nous sommes le lundi matin avant 9h, alors nous continuons afficher Bon week-end . Sinon, si nous sommes dans la tranche horaire 9h 18h alors nous pouvons appeler la mthode qui affiche Bonjour. Si non, il reste juste vrifier que nous ne sommes pas vendredi soir, qui fait partie du week-end, sinon on peut afficher le message de Bonsoir . Et voil, un bon exercice pour manipuler les conditions et les numrations

Aller plus loin


Ce TP ntait pas trs compliqu, il nous a permis de vrifier que nous avions bien compris le principe des if et que nous sachions appeler des lments du framework .NET. Nous aurions pu simplifier lcriture de lapplication en compliquant en peu les tests avec une combinaison de conditions. Par exemple, on pourrait avoir : Code : C# if (DateTime.Now.DayOfWeek == DayOfWeek.Saturday || DateTime.Now.DayOfWeek == DayOfWeek.Sunday || (DateTime.Now.DayOfWeek == DayOfWeek.Monday && DateTime.Now.Hour < 9) || (DateTime.Now.DayOfWeek == DayOfWeek.Friday && DateTime.Now.Hour >= 18)) { // nous sommes le week-end AfficherBonWeekEnd(); } else { // nous sommes en semaine if (DateTime.Now.Hour >= 9 && DateTime.Now.Hour < 18) { // nous sommes dans la journe AfficherBonjour(); } else { AfficherBonsoir(); } }

Le premier test permet de vrifier que nous sommes soit samedi, soit dimanche, soit que nous sommes lundi et que lheure est infrieure 9, soit que nous sommes vendredi et que lheure est suprieure 18. Nous avons, pour ce faire, combin les tests avec loprateur logique OU : ||. Remarquons que les parenthses nous permettent dagir sur lordre dvaluation des conditions. Pour que ce soit le week-end, il faut bien sr tre vendredi et que lheure soit suprieure 18 ou lundi et que lheure soit infrieure 9 ou samedi ou dimanche. On pourrait encore simplifier en vitant de solliciter chaque fois le framework .NET pour obtenir la date courante. Il suffit de stocker la date courante dans une variable de type DateTime. Ce qui donnerait : Code : C# DateTime dateCourante = DateTime.Now; if (dateCourante.DayOfWeek == DayOfWeek.Saturday || dateCourante.DayOfWeek == DayOfWeek.Sunday || (dateCourante.DayOfWeek == DayOfWeek.Monday && dateCourante.Hour

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


< 9) || (dateCourante.DayOfWeek == DayOfWeek.Friday && dateCourante.Hour >= 18)) { // nous sommes le week-end AfficherBonWeekEnd(); } else { // nous sommes en semaine if (dateCourante.Hour >= 9 && dateCourante.Hour < 18) { // nous sommes dans la journe AfficherBonjour(); } else { AfficherBonsoir(); } }

79/381

On utilise ici le type DateTime comme le type string ou int. Il sert grer les dates et lheure. Il est lgrement diffrent des types que nous avons vus pour linstant, nous ne nous attarderons pas dessus. Nous aurons loccasion de dcouvrir de quoi il sagit dans la partie suivante. Cette optimisation na rien dextraordinaire, mais cela nous vite un appel chaque fois au framework .NET. V pour ce TP. Jespre que vous aurez russi avec brio lexercice. oil V ous avez pu remarquer que ce TP n'tait pas trop difficile. Il a simplement fallu rflchir comment imbriquer correctement nos conditions. N'hsitez pas pratiquer et vous entraner avec d'autres problmes de votre cru. Si vous avez le moindre problme, vous pouvez relire les chapitres prcdents. V ous verrez que nous aurons l'occasion d'normment utiliser ces instructions conditionnelles dans tous les programmes que nous allons crire.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

80/381

Les boucles
Nous les avons voques rapidement un peu plus tt en parlant des tableaux et des listes. Dans ce chapitre nous allons dcrire plus prcisment les boucles. Elles sont souvent utilises pour parcourir des lments numrables, comme le sont les tableaux ou les listes. Elles peuvent galement tre utilises pour effectuer la mme action tant qu'une condition n'est pas ralise.

La boucle For
La premire instruction que nous avons aperue est la boucle for. Elle permet de rpter un bout de code tant quune condition est vraie. Souvent cette condition est un compteur. Nous pouvons par exemple afficher un message 50 fois avec le code suivant : Code : C# int compteur; for (compteur = 0; compteur < 50; compteur++) { Console.WriteLine("Bonjour C#"); }

Ce qui donne :

Nous dfinissons ici un entier compteur . Il est initialis 0 en dbut de boucle (compteur = 0). Aprs chaque excution du bloc de code du for, cest--dire chaque itration, il va afficher Bonjour C# . la fin de chaque itration, la variable compteur est incrmente (compteur++) et nous recommenons lopration tant que la condition compteur < 50 est vraie. Bien sr, la variable compteur est accessible dans la boucle et change de valeur chaque itration. Code : C# int compteur; for (compteur = 0; compteur < 50; compteur++) { Console.WriteLine("Bonjour C# " + compteur); }

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Ce qui donne :

81/381

Ce prcdent code affichera la valeur de la variable aprs chaque bonjour, donc de 0 49. En effet, quand compteur passe 50, la condition nest plus vraie et on passe aux instructions suivantes. En gnral, on utilise la boucle for pour parcourir un tableau. Ainsi, nous pourrons utiliser le compteur comme indice pour accder aux lments du tableau : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; int indice; for (indice = 0; indice < 7; indice++) { Console.WriteLine(jours[indice]); }

Dans cette boucle, comme la premire itration indice vaut 0, nous afficherons llment du tableau la position 0, savoir Lundi . litration suivante, indice passe 1, nous affichons llment du tableau la position 1, savoir Mardi , et ainsi de suite. Ce qui donne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

82/381

Attention ce que lindice ne dpasse pas la taille du tableau, sinon laccs un indice en dehors des limites du tableau provoquera une erreur lexcution. Pour viter ceci, on utilise en gnral la taille du tableau comme condition de fin : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; int indice; for (indice = 0; indice < jours.Length; indice++) { Console.WriteLine(jours[indice]); }

Ici jours.Length renvoie la taille du tableau, savoir 7. Il est trs courant de boucler sur un tableau en passant tous les lments un par un, mais il est possible de changer les conditions de dpart, les conditions de fin, et llment qui influe sur la condition de fin. Ainsi, lexemple suivant : Code : C# int[] chiffres = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; for (int i = 9; i > 0; i -= 2) { Console.WriteLine(chiffres[i]); }

Permet de parcourir le tableau de 2 en 2 en commenant par la fin. Ce qui nous donne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

83/381

V ous avez pu voir que dans cet exemple, nous avons dfini lentier i directement dans linstruction for, cest une commodit qui nous permet davoir la variable i qui nexiste qu lintrieur de la boucle, car sa porte correspond aux accolades qui dlimitent le for. Attention, il est possible de faire un peu tout et nimporte quoi dans ces boucles. Aussi il peut arriver que lon se retrouve avec des bugs, comme des boucles infinies. Par exemple, le code suivant : Code : C# for (int indice = 0; indice < 7; indice--) { Console.WriteLine("Test" + indice); }

est une boucle infinie. En effet, on modifie la variable indice en la dcrmentant. Sauf que la condition de sortie de la boucle est valable pour un indice qui dpasse ou gale la valeur 7, ce qui narrivera jamais. Si on excute lapplication avec ce code, la console va afficher linfini le mot Test avec son indice. La seule solution pour quitter le programme sera de fermer brutalement lapplication. Lautre solution est dattendre que le programme se termine... Mais tu viens de dire que la boucle tait infinie ?

Oui cest vrai, mais en fait, ici on se heurte un cas limite du C#. Cest cause de la variable indice. indice est un entier que lon dcrmente. Au dbut il vaut zro, puis -1, puis -2, etc Lorsque la variable indice arrive la limite infrieure que le type int est capable de grer, cest--dire -2147483648 alors il y a ce quon appelle un dpassement de capacit. Sans rentrer dans les dtails, il ne peut pas stocker un entier plus petit et donc il boucle et repart lentier le plus grand, cest--dire 2147483647. Donc pour rsumer, lindice fait :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


0 -1 -2 ... -2147483647 -2147483648 +2147483647

84/381

Et comme l, il se retrouve suprieur 7, la boucle se termine.

Donc, techniquement, ce nest pas une boucle infinie, mais bon, on a attendu tellement longtemps pour atteindre ce cas limite que cest tout comme. Et surtout, nous tombons sur un cas imprvu. Ici, a se termine plutt bien , mais a aurait pu finir en crash de lapplication. Dans tous les cas, il faut absolument matriser ses conditions de sortie de boucle pour viter la boucle infinie, un des cauchemars du dveloppeur !

La boucle Foreach
Comme il est trs courant dutiliser les boucles pour parcourir un tableau ou une liste, le C# dispose dun oprateur particulier : foreach que lon peut traduire par pour chaque : pour chaque lment du tableau faire Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; foreach (string jour in jours) { Console.WriteLine(jour); }

Cette boucle va nous permettre de parcourir tous les lments du tableau jours . chaque itration, la boucle va crer une chaine de caractres jour qui contiendra llment courant du tableau. noter que la variable jour aura une porte gale

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

85/381

au bloc foreach. Nous pourrons ainsi utiliser cette valeur dans le corps de la boucle et pourquoi pas lafficher comme dans lexemple prcdent. Ce qui produira :

Linstruction foreach fonctionne aussi avec les listes, par exemple le code suivant : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; foreach (string jour in jours) { Console.WriteLine(jour); }

nous permettra dafficher tous les jours de la semaine contenus dans la liste des jours. Attention, la boucle foreach est une boucle en lecture seule. Cela veut dire qu'il n'est pas possible de modifier l'lment de l'itration en cours. Par exemple, le code suivant : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; foreach (string jour in jours) { jour = "pas de jour !"; }

provoquera l'erreur de compilation suivante :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


Citation : Compilateur Impossible d'assigner 'jour', car il s'agit d'un 'variable d'itration foreach'

86/381

Notez d'ailleurs que l'quipe de traduction de Visual C# express a quelques progrs faire

...

Si nous souhaitons utiliser une boucle pour changer la valeur de notre liste ou de notre tableau, il faudra passer par une boucle for : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; for (int i = 0; i < jours.Count; i++ ) { jours[i] = "pas de jour !"; }

Il vous arrivera aussi surement un jour (a arrive tous les dveloppeurs) de vouloir modifier une liste en elle mme lors d'une boucle foreach. C'est--dire lui rajouter un lment, le supprimer, etc ... C'est galement impossible car partir du moment o l'on rentre dans la boucle foreach, la liste devient non-modifiable. Prenons l'exemple combien classique de la recherche d'une valeur dans une liste pour la supprimer. Nous serions tent de faire : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; foreach (string jour in jours) { if (jour == "Mercredi") jours.Remove(jour); }

ce qui semblerait tout fait correct et en plus, ne provoque pas d'erreur de compilation. Sauf que si vous excutez l'application, vous aurez l'erreur suivante :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

87/381

qui nous plante notre application. Le programme nous indique que la collection a t modifie et que l'opration d'numration peut ne pas s'excuter . Il est donc impossible de faire notre suppression ainsi. Comment tu ferais toi ?

Et bien, plusieurs solutions existent. Celle qui vient en premier l'esprit est d'utiliser une boucle for par exemple : Code : C# for (int i = 0 ; i < jours.Count ; i++) { if (jours[i]== "Mercredi") jours.Remove(jours[i]); }

Cette solution est intressante ici, mais elle peut poser un problme dans d'autres situations. En effet, vu que nous supprimons un lment de la liste, nous allons nous retrouver avec une incohrence entre l'indice en cours et l'lment que nous essayons d'atteindre. En effet, lorsque le jour courant est Mercredi, l'indice i vaut 2. Si l'on supprime cet lment, c'est Jeudi qui va se retrouver en position 2. Et nous allons rater son analyse car la boucle va continuer l'indice 3, qui sera Vendredi. On peut viter ce problme en parcourant la boucle l'envers : Code : C# for (int i = jours.Count - 1; i >= 0; i--) { if (jours[i] == "Mercredi") jours.Remove(jours[i]); }

A noter que d'une manire gnrale, il ne faut pas modifier les collections que nous sommes en train de parcourir.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

88/381

Nous n'tudierons pas les autres solutions car elles font appels des notions que nous verrons en dtail plus tard. Aprs avoir lu ceci, vous pourriez avoir l'impression que la boucle foreach n'est pas souple et difficilement exploitable, autant utiliser autre chose ... V ous verrez l'utilisation que non, elle est en fait trs pratique. Il faut simplement connatre ses limites. V qui est chose faite. oil

Nous avons vu que linstruction foreach permettait de boucler sur tous les lments dun tableau ou dune liste. En fait, il est possible de parcourir tous les types qui sont numrables. Nous verrons plus loin ce qui caractrise un type numrable, car pour linstant, cest un secret ! Chuuut .

La boucle While
La boucle while est en gnral moins utilise que for ou foreach. Cest la boucle qui va nous permettre de faire quelque chose tant quune condition nest pas vrifie. Elle ressemble de loin la boucle for, mais la boucle for se spcialise dans le parcours de tableau tandis que la boucle while est plus gnrique. Par exemple : Code : C# int i = 0; while (i < 50) { Console.WriteLine("Bonjour C#"); i++; }

Permet dcrire Bonjour C# 50 fois de suite. Ici, la condition du while est value en dbut de boucle. Dans lexemple suivant : Code : C# int i = 0; do { Console.WriteLine("Bonjour C#"); i++; } while (i < 50);

La condition de sortie de boucle est value la fin de la boucle. Lutilisation du mot cl do permet dindiquer le dbut de la boucle. Concrtement cela veut dire que dans le premier exemple, le code lintrieur de la boucle peut ne jamais tre excut, si par exemple lentier i est initialis 50. A contrario, on passera au moins une fois dans le corps de la boucle du second exemple, mme si lentier i est initialis 50 car la condition de sortie de boucle est value la fin. Les conditions de sorties de boucles ne portent pas forcment sur un compteur ou un indice, nimporte quelle expression peut tre value. Par exemple : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; int i = 0; bool trouve = false;

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


while (!trouve) { string valeur = jours[i]; if (valeur == "Jeudi") { trouve = true; } else { i++; } } Console.WriteLine("Trouv l'indice " + i);

89/381

Le code prcdant va rpter les instructions contenues dans la boucle while tant que le boolen trouve sera faux (c'est-dire quon va sarrter ds que le boolen sera vrai). Nous analysons la valeur lindice i, si la valeur est celle cherche, alors nous passons le boolen vrai et nous pourrons sortir de la boucle. Sinon, nous incrmentons lindice pour passer au suivant. Attention encore aux valeurs de sorties de la boucle. Si nous ne trouvons pas la chaine recherche, alors i continuera sincrmenter ; le boolen ne passera jamais vrai, nous resterons bloqu dans la boucle et nous risquons datteindre un indice qui nexiste pas dans le tableau. Il serait plus prudent que la condition porte galement sur la taille du tableau, par exemple : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; int i = 0; bool trouve = false; while (i < jours.Length && !trouve) { string valeur = jours[i]; if (valeur == "Jeudi") { trouve = true; } else { i++; } } if (!trouve) Console.WriteLine("Valeur non trouve"); else Console.WriteLine("Trouv l'indice " + i);

Ainsi, si lindice est suprieur la taille du tableau, nous sortons de la boucle et nous liminons le risque de boucle infinie. Une erreur classique est que la condition ne devienne jamais vraie cause dune erreur de programmation. Par exemple, si joublie dincrmenter la variable i, alors chaque passage de la boucle janalyserai toujours la premire valeur du tableau et je natteindrai jamais la taille maximale du tableau, condition qui me permettrait de sortir de la boucle. Je ne le rpterai jamais assez : bien faire attention aux conditions de sortie dune boucle.

Les instructions break et continue


Il est possible de sortir prmaturment dune boucle grce linstruction break. Ds quelle est rencontre, elle sort du bloc de code de la boucle. Lexcution du programme continue alors avec les instructions situes aprs la boucle. Par exemple : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


int i = 0; while (true) { if (i >= 50) { break; } Console.WriteLine("Bonjour C#"); i++; }

90/381

Le code prcdent pourrait potentiellement produire une boucle infinie. En effet, la condition de sortie du while est toujours vraie. Mais lutilisation du mot cl break nous permettra de sortir de la boucle ds que i atteindra la valeur 50. Certes ici, il suffirait que la condition de sortie porte sur lvaluation de lentier i. Mais il peut arriver des cas o il pourra tre judicieux dutiliser un break (surtout lors d'un dmnagement !). Cest le cas pour lexemple suivant. Imaginons que nous voulions vrifier la prsence dune valeur dans une liste. Pour la trouver, on peut parcourir les lments de la liste et une fois trouve, on peut sarrter. En effet, il sera inutile de continuer parcourir le reste des lments : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; bool trouve = false; foreach (string jour in jours) { if (jour == "Jeudi") { trouve = true; break; } }

Nous nous conomisons ici danalyser les 3 derniers lments de la liste. Il est galement possible de passer litration suivante dune boucle grce lutilisation du mot-cl continue. Prenons lexemple suivant : Code : C# for (int i = 0; i < 20; i++) { if (i % 2 == 0) { continue; } Console.WriteLine(i); }

Ici, loprateur % est appel modulo . Il permet dobtenir le reste de la division. Lopration i % 2 renverra donc 0 quand i sera pair. Ainsi, ds quun nombre pair est trouv, nous passons litration suivante grce au mot cl continue. Ce qui fait que nous n'allons afficher que les nombres impairs. Ce qui donne :

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

91/381

Bien sr, il aurait t possible dinverser la condition du if pour ne faire le Console.WriteLine() que dans le cas o i % 2 != 0. vous de choisir lcriture que vous prfrez en fonction des cas que vous rencontrerez.

En rsum
On utilise la boucle for pour rpter des instructions tant qu'une condition n'est pas vrifie, les lments de la condition changeant chaque itration. On utilise en gnral la boucle for pour parcourir un tableau, avec un indice qui s'incrmente chaque itration. La boucle foreach est utilise pour simplifier le parcours des tableaux ou des listes. La boucle while permet de rpter des instructions tant qu'une condition n'est pas vrifie. C'est la boucle la plus souple. Il faut faire attention aux conditions de sortie d'une boucle afin d'viter les boucles infinies qui font planter l'application.

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

92/381

TP : Calculs en boucle
a y est, grce au chapitre prcdent, vous devez avoir une bonne ide de ce que sont les boucles. Par contre, vous ne voyez peut-tre pas encore compltement qu'elles vont vous servir tout le temps. C'est un lment qu'il est primordial de matriser. Il vous faut donc vous entrainer pour tre bien sr davoir tout compris. Cest justement lobjectif de ce deuxime TP. Finie la thorie des boucles, place la pratique en boucle ! Notre but est de raliser des calculs qui vont avoir besoin des for et des foreach. V ous tes prts ? Alors, c'est parti

Instructions pour raliser le TP


Le but de ce TP va tre de crer 3 mthodes. La premire va servir calculer la sommes d'entiers conscutifs. Si par exemple je veux calculer la somme des entiers de 1 10, c'est dire 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10, je vais appeler cette mthode en lui passant en paramtres 1 et 10, c'est--dire les bornes des entiers dont il faut faire la somme. Quelque chose du genre : Code : C# Console.WriteLine(CalculSommeEntiers(1, 10)); Console.WriteLine(CalculSommeEntiers(1, 100));

Sachant que le premier rsultat de cet exemple vaut 55 (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 = 55) et le deuxime 5050. La deuxime mthode acceptera une liste de double en paramtres et devra renvoyer la moyenne des doubles de la liste. Par exemple : Code : C# List<double> liste = new List<double> { 1.0, 5.5, 9.9, 2.8, 9.6}; Console.WriteLine(CalculMoyenne(liste));

Le rsultat de cet exemple vaut 5.76. Enfin, la dernire mthode devra dans un premier temps construire une liste dentiers de 1 100 qui sont des multiples de 3 (3, 6, 9, 12, ). Dans un second temps, construire une autre liste dentiers de 1 100 qui sont des multiples de 5 (5, 10, 15, 20, ). Et dans un dernier temps, il faudra calculer la somme des entiers qui sont communs aux deux listes vous devez bien sur trouver 315 comme rsultat V oil, cest vous de jouer Bon, allez, je vais quand mme vous donner quelques conseils pour dmarrer. V ous ntes pas oblig de les lire si vous vous sentez capables de raliser cet exercice tout seul. V ous laurez videmment compris, il va falloir utiliser des boucles. Je ne donnerai pas de conseils pour la premire mthode, cest juste pour vous chauffer .

Pour la deuxime mthode, vous allez avoir besoin de diviser la somme de tous les doubles par la taille de la liste. V ous ne savez sans doute pas comment obtenir cette taille. Le principe est le mme que pour la taille dun tableau et vous laurez sans doute trouv si vous fouillez un peu dans les mthodes de la liste. Toujours est-il que pour obtenir la taille dune liste, on va utiliser liste.Count, avec par exemple : Code : C# int taille = liste.Count;

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

93/381

Enfin, pour la dernire mthode, vous allez devoir trouver tous les multiples de 3 et de 5. Le plus simple, mon avis, pour calculer tous les multiples de 3, est de faire une boucle qui dmarre 3 et davancer de 3 en 3 jusqu la valeur souhaite. Et pareil pour les multiples de 5. Ensuite, il sera ncessaire de faire deux boucles imbriques afin de dterminer les intersections. Cest--dire parcourir la liste de multiple de 3 et lintrieur de cette boucle, parcourir la liste des multiples de 5. On compare les deux lments, sils sont gaux, cest quils sont communs aux deux listes. V oil, vous devriez avoir tous les lments en main pour russir ce TP, c'est vous

Correction
Jimagine que vous avez russi ce TP, non pas sans difficults, mais force de ttonnements, vous avez sans doute russi. Bravo. Si vous navez mme pas essay, pas bravo . Quoi quil en soit, voici la correction que je propose. Premire mthode : Code : C# static int CalculSommeEntiers(int borneMin, int borneMax) { int resulat = 0; for (int i = borneMin; i <= borneMax ; i++) { resulat += i; } return resulat; }

Ce ntait pas trs compliqu, il faut dans un premier temps construire une mthode qui renvoie un entier et qui accepte deux entiers en paramtres. Ensuite, on boucle grce linstruction for de la borne infrieure la borne suprieure (incluse, donc il faut utiliser loprateur de comparaison <= ) en incrmentant un compteur de 1 chaque itration. Nous ajoutons la valeur du compteur un rsultat, que nous retournons en fin de boucle. Seconde mthode : Code : C# static double CalculMoyenne(List<double> liste) { double somme = 0; foreach (double valeur in liste) { somme += valeur; } return somme / liste.Count; }

Ici, le principe est grosso modo le mme, la diffrence est que la mthode retourne un double et accepte une liste de double en paramtres. Ici, nous utilisons la boucle foreach pour parcourir tous les lments que nous ajoutons un rsultat. Enfin, nous retournons ce rsultat divis par la taille de la liste. Troisime mthode : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#

94/381

static int CalculSommeIntersection() { List<int> multiplesDe3 = new List<int>(); List<int> multiplesDe5 = new List<int>(); for (int i = 3; i <= 100; i += 3) { multiplesDe3.Add(i); } for (int i = 5; i <= 100; i += 5) { multiplesDe5.Add(i); } int somme = 0; foreach (int m3 in multiplesDe3) { foreach (int m5 in multiplesDe5) { if (m3 == m5) somme += m3; } } return somme;

Peut-tre la plus complique... On commence par crer nos deux listes de multiples. Comme je vous avais conseill, jutilise une boucle for qui commence trois avec un incrment de 3. Comme a, je suis sr davoir tous les multiples de 3 dans ma liste. Cest le mme principe pour les multiples de 5, sachant que dans les deux cas, la condition de sortie est quand lindice est suprieur 100. Ensuite, jai mes deux boucles imbriques o je compare les deux valeurs et si elles sont gales, je rajoute la valeur la somme globale que je renvoie en fin de mthode. Pour bien comprendre ce quil se passe dans les boucles imbriques, il faut comprendre que nous allons parcourir une unique fois la liste multiplesDe3 mais que nous allons parcourir autant de fois la liste multipleDe5 quil y a dlments dans la liste multipleDe3, cest--dire 33 fois. Ce nest sans doute pas facile de le concevoir ds le dbut, mais pour vous aider, vous pouvez essayer de vous faire lalgorithme dans la tte : On rentre dans la boucle qui parcoure la liste multiplesDe3 m3 vaut 3 On rentre dans la boucle qui parcoure la liste multiplesDe5 m5 vaut 5 On compare 3 5, ils sont diffrents On passe litration suivante de la liste multiplesDe5 m5 vaut 10 On compare 3 10, ils sont diffrents Etc jusqu ce quon ait fini de parcourir la liste des multiplesDe5 On passe litration suivante de la liste multiplesDe3 m3 vaut 6 On rentre dans la boucle qui parcoure la liste multiplesDe5 m5 vaut 5 On compare 6 5, ils sont diffrents On passe litration suivante de la liste multiplesDe5 Etc

Aller plus loin


V ous avez remarqu que dans la deuxime mthode, jutilise une boucle foreach pour parcourir la liste : Code : C#

www.siteduzero.com

Partie 1 : Les rudiments du langage C#


static double CalculMoyenne(List<double> liste) { double somme = 0; foreach (double valeur in liste) { somme += valeur; } return somme / liste.Count; }

95/381

Il est aussi possible de parcourir les listes avec un for et daccder aux lments de la liste avec un indice, comme on le fait pour un tableau. Ce qui donnerait : Code : C# static double CalculMoyenne(List<double> liste) { double somme = 0; for (int i = 0; i < liste.Count; i++) { somme += liste[i]; } return somme / liste.Count; }

Notez quon se sert de liste.Count pour obtenir la taille de la liste et quon accde llment courant avec liste[i]. Je reconnais que la boucle foreach est plus explicite, mais cela peut tre utile de connaitre le parcours dune liste avec la boucle for. A vous de voir. V ous aurez galement not ma technique pour avoir des multiples de 3 et de 5. Il y en a plein dautres. Je pense une en particulier et qui fait appel des notions que nous avons vu auparavant : la division entire et la division de double. Pour savoir si un nombre est un multiple dun autre, il suffit de les diviser entre eux et de voir sil y a un reste la division. Pour ce faire, on peut le faire de deux faons. Soit en comparant la division entire avec la division double et en vrifiant que le rsultat est le mme. Si le rsultat est le mme, cest quil ny a pas de chiffres aprs la virgule : Code : C# for (int i = 1; i <= 100; i++) { if (i / 3 == i / 3.0) multiplesDe3.Add(i); if (i / 5 == i / 5.0) multiplesDe5.Add(i); }

Cette technique fait appel des notions que nous navons pas encore vues : comment cela se fait-il quon puisse comparer un entier un double ? Nous le verrons un peu plus tard.

L'autre solution est d'utiliser loprateur modulo que nous avons vu prcdemment qui fait justement a : Code : C# for (int i = 1; i <= 100; i++) { if (i % 3 == 0)

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


multiplesDe3.Add(i); if (i % 5 == 0) multiplesDe5.Add(i);

96/381

Lavantage de ces deux techniques est quon peut construire les deux listes de multiples en une seule boucle. V oil, cest fini pour ce TP. Nhsitez pas vous faire la main sur ces boucles car il est fondamental que vous les maitrisiez. Faites-vous plaisir, tentez de les repousser dans leurs limites, essayez de rsoudre dautres problmes, ... Limportant, cest de pratiquer. Cette premire partie touche dsormais sa fin. Nous avons commenc l'tude du C# en dfinissant exactement ce que nous allions faire dans ce tutoriel, ce qu'est le C# et comment crer des applications avec. V ous avez pu dcouvrir tout au long des diffrents chapitres les bases de la programmation en C#. V ous devriez commencer tre capables de vous amuser faire quelques petits programmes. Dans le prochain chapitre, nous allons aller encore un peu plus loin dans l'tude des bases du C#.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

97/381

Partie 2 : Un peu plus loin avec le C#


Dans cette partie, nous allons pousser un peu plus loin notre tude des bases du C#. V ous avez vu lessentiel de lessentiel dans la partie prcdente, et vous aurez loccasion de revoir et dutiliser constamment ce que nous avons vu. Ici, nous allons commencer ajouter un peu d'interactivit nos programmes, puis nous verrons comment utiliser Visual C# express pour amliorer nos dveloppements. Enfin, autour de petits TP, vous pourrez mettre en pratique vos connaissances. V ous tes prts ? Cest parti.

Les conversions entre les types


Nous avons vu que le C# est un langage qui possde plein de types de donnes diffrents : entier, dcimal, chane de caractres, etc. Dans nos programmes, nous allons trs souvent avoir besoin de manipuler des donnes entre elles alors qu'elles ne sont pas forcment du mme type. Lorsque cela sera possible, nous aurons besoin de convertir un type de donnes en un autre.

Entre les types compatibles : Le casting


Cest lheure de faire la slection des types les plus performants, place au casting ! Le jury est en place, vos SMS pour voter. Ah, on me fait signe quil ne sagirait pas de ce casting l .

Le casting est simplement laction de convertir la valeur dun type dans un autre.

Plus prcisment, cela fonctionne pour les types qui sont compatibles entre eux, entendez par l qui se ressemblent . Par exemple, l'entier et le petit entier se ressemblent. Pour rappel, nous avons : Type Description

short Entier de -32768 32767 int Entier de -2147483648 2147483647

Ils ne diffrent que par leur capacit. Le short ne pourra pas contenir le nombre 100000 par exemple, alors que l'int le pourra. Nous ne l'avons pas encore fait, mais le C# nous autorise faire : Code : C# short s = 200; int i = s;

Car il est toujours possible de stocker un petit entier dans un grand. Peu importe la valeur de s, i sera toujours mme de contenir sa valeur. C'est comme dans une voiture, si nous arrivons tenir 5 dans un monospace, nous pourrons facilement tenir 5 dans un bus. L'inverse n'est pas vrai bien sr, si nous tenons 100 dans un bus, ce n'est pas certain que nous pourrons tenir dans le monospace, mme en se serrant bien. Ce qui fait que si nous faisons : Code : C#

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


int i = 100000; short s = i;

98/381

nous aurons l'erreur de compilation suivante : Code : Console Impossible de convertir implicitement le type 'int' en 'short'. Une conversion explicite il manquant ?)

Et oui, comment pouvons-nous faire rentrer 100000 dans un type qui ne peut aller que jusqu' 32767 ? Le compilateur le sait bien. V ous remarquerez que nous aurons cependant la mme erreur si nous tentons de faire : Code : C# int i = 200; short s = i;

Mais pourquoi ? Le short est bien capable de stocker la valeur 200 ?

Oui tout fait, mais le compilateur nous avertit quand mme. Il nous dit :

Attention, vous essayez de faire rentrer les personnes du bus dans un monospace, tes-vous bien sr ?

Nous avons envie de lui rpondre :

Oui oui, je sais qu'il y a trs peu de personnes dans le bus et qu'ils pourront rentrer sans aucun problme dans le monospace. Fais moi confiance !

(on se parle souvent avec mon compilateur !)

Et bien, ceci s'crit en C# de la manire suivante : Code : C# int i = 200; short s = (short)i;

Nous utilisons ce qu'on appelle un cast explicite.

Pour faire un tel cast, il suffit de prcder la variable convertir du nom du type souhait entre parenthses. Ce qui permet d'indiquer notre compilateur que nous savons ce que nous faisons, et que l'entier tiendra correctement dans le petit entier.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

99/381

Mais attention, le compilateur nous fait confiance. Nous sommes le boss ! Cela implique une certaine responsabilit, il ne faut pas faire n'importe quoi. Si nous faisons : Code : C# int i = 40000; short s = (short)i; Console.WriteLine(s); Console.WriteLine(i);

nous tentons de faire rentrer un trop gros entier dans ce qu'est capable de stocker le petit entier. Si nous excutons notre application, nous aurons :

Le rsultat n'est pas du tout celui attendu. Nous avons fait n'importe quoi, le C# nous a punis. En fait, plus prcisment, il s'est pass ce qu'on appelle un dpassement de capacit. Nous l'avons dj vu lors du chapitre sur les boucles. Ici, il s'est produit la mme chose. Le petit entier est all sa valeur maximale puis a boucl en repartant de sa valeur minimale. Bref, tout a pour dire que nous obtenons un rsultat inattendu. Il faut donc faire attention ce que l'on fait et honorer la confiance que nous porte le compilateur. Bien faire attention ce que l'on caste. Caste ... Remarquons cet anglicisme. Nous utiliserons souvent le verbe caster, qui signifiera bien sr que nous convertissons des types qui se ressemblent entre eux, pour le plus grand malheur des professeurs de franais. D'une faon similaire l'entier et au petit entier, l'entier et le double se ressemblent un peu. Ce sont tous les deux des types permettant de contenir des nombres. Le premier permet de contenir des nombres entiers, le deuxime pouvant contenir des nombres virgules. Ainsi, nous pouvons faire le code C# suivant : Code : C#

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


int i = 20; double d = i;

100/381

En effet, un double est plus prcis quun entier. Il est capable davoir des chiffres aprs la virgule alors que lentier ne le peut pas. Ce qui fait que le double est entirement capable de stocker toute la valeur dun entier sans perdre dinformation dans cette affectation. Par contre, comme on peut s'y attendre, linverse nest pas possible. Le code suivant : Code : C# double prix = 125.55; int valeur = prix;

produira lerreur de compilation suivante : Code : Console

Impossible de convertir implicitement le type 'double' en 'int'. Une conversion explicite il manquant ?)

En effet, un double tant plus prcis quun entier, si nous mettons ce double dans lentier nous allons perdre notamment les chiffres aprs la virgule. Il restera encore une fois demander au compilateur de nous faire confiance ! Ok, ceci est un double, mais ce nest pas grave, je veux lutiliser comme un entier ! Oui oui, mme si je sais que je vais perdre les chiffres aprs la virgule .

Ce qui scrit en C# de cette manire, comme nous l'avons vu : Code : C# double prix = 125.55; int valeur = (int)prix; // valeur vaut 125

Nous faisons prcder la variable prix du type dans lequel nous voulons la convertir en utilisant les parenthses. En loccurrence, on peut se servir de ce cast pour rcuprer la partie entire d'un nombre virgule.

C'est plutt sympa comme instruction. Mais n'oubliez-pas que cette opration est possible uniquement avec les types qui se ressemblent entre eux. Par exemple, le cast suivant est impossible : Code : C# string nombre = "123"; int valeur = (int)nombre;

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

101/381

car les deux types sont trop diffrents et sont incompatibles entre eux. Mme si la chaine de caractres reprsente un nombre. Nous verrons plus loin comment convertir une chane en entier. Pour linstant, Visual C# Express nous gnre une erreur de compilation : Code : Console Impossible de convertir le type 'string' en 'int'

Le message derreur est plutt explicite. Il ne nous propose mme pas d'utiliser de cast, il considre que les types sont vraiment trop diffrents !

Nous avons vu prcdemment que les numrations reprsentaient des valeurs entires. Il est donc possible de rcuprer lentier correspondant une valeur de lnumration grce un cast. Par exemple, en considrant lnumration suivante : Code : C# enum Jours { Lundi = 5, // lundi vaut 5 Mardi, // mardi vaut 6 Mercredi = 9, // mercredi vaut 9 Jeudi = 10, // jeudi vaut 10 Vendredi, // vendredi vaut 11 Samedi, // samedi vaut 12 Dimanche = 20 // dimanche vaut 20 }

Le code suivant : Code : C# int valeur = (int)Jours.Lundi; // valeur vaut 5

convertit lnumration en entier. Nous verrons dans la prochaine partie que le cast est beaucoup plus puissant que a, mais pour linstant, nous navons pas assez de connaissances pour tout tudier. Nous y reviendrons dans la partie suivante.

Entre les types incompatibles


Nous avons vu quil tait facile de convertir des types qui se ressemblent grce au cast. Il est parfois possible de convertir des types qui ne se ressemblent pas mais qui ont le mme sens. Par exemple, il est possible de convertir une chaine de caractres qui contient uniquement des chiffres en un nombre (entier, dcimal, ). Cette conversion va nous servir normment car ds quun utilisateur va saisir une information par le clavier, elle sera reprsente par une chaine de caractres. Donc si on lui demande de saisir un nombre, il faut tre capable dutiliser sa saisie comme un nombre afin de le transformer, de le stocker, etc Pour ce faire, il existe plusieurs solutions. La plus simple est dutiliser la mthode Convert.ToInt32() disponible dans le framework .NET. Par exemple : Code : C# string chaineAge = "20"; int age = Convert.ToInt32(chaineAge); // age vaut 20

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

102/381

Cette mthode, bien que simple dutilisation, pose un inconvnient dans le cas o la chaine ne reprsente pas un entier. ce moment-l, la conversion va chouer et le C# va renvoyer une erreur au moment de lexcution. Par exemple : Code : C# string chaineAge = "vingt ans"; int age = Convert.ToInt32(chaineAge);

Si vous excutez ce bout de code, vous verrez :

La console nous affiche ce que lon appelle une exception. Il sagit tout simplement dune erreur. Nous aurons loccasion dtudier plus en dtail les exceptions dans les chapitres ultrieurs. Pour linstant, on a juste besoin de voir que ceci ne nous convient pas. Lerreur est explicite Le format de la chaine dentre est incorrect , mais cela se passe au moment de lexcution et notre programme plante lamentablement. Nous verrons dans le chapitre sur les exceptions comment grer les erreurs. En interne, la mthode Convert.ToInt32() utilise une autre mthode pour faire la conversion, il sagit de la mthode int.Parse(). Donc plutt que dutiliser une mthode qui en appelle une autre, nous pouvons nous en servir directement, par exemple : Code : C# string chaineAge = "20"; int age = int.Parse(chaineAge); // age vaut 20

Bien sr, il se passera exactement la mme chose que prcdemment quand la chaine ne reprsentera pas un entier correct. Il existe par contre une autre faon de convertir une chaine en entier qui ne provoque pas derreur quand le format nest pas correct et qui nous informe si la conversion sest bien passe ou non, cest la mthode int.TryParse() qui sutilise ainsi : Code : C# string chaineAge = "ab20cd";

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


int age; if (int.TryParse(chaineAge, out age)) { Console.WriteLine("La conversion est possible, age vaut " + age); } else { Console.WriteLine("Conversion impossible"); }

103/381

Et nous aurons :

La mthode int.TryParse nous renvoie vrai si la conversion est bonne, faux sinon. Nous pouvons donc effectuer une action en fonction du rsultat grce aux if/else. On passe en paramtres la chaine convertir et la variable o lon veut stocker le rsultat de la conversion. Le mot cl out signifie juste que la variable est modifie par la mthode, nous verrons exactement de quoi il sagit dans un chapitre ultrieur. Les mthodes que nous venons de voir Convert.ToString() ou int.TryParse() se dclinent en gnral pour tous les types de bases, par exemple double.TryParse() ou Convert.ToDecimal(), etc

En rsum

Il est possible, avec le casting, de convertir la valeur dun type dans un autre lorsquils sont compatibles entre eux. Le casting explicite sutilise en prfixant une variable par un type prcis entre parenthses. Le framework .NET possde des mthodes permettant de convertir des types incompatibles entre eux sils sont smantiquement proches.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

104/381

Lire le clavier dans la console


Nous avons beaucoup crit avec Console.WriteLine(), maintenant il est temps de savoir lire. En l'occurrence, il faut tre capable de rcuprer ce que l'utilisateur a saisi au clavier. En effet, un programme qui n'a pas d'interaction avec l'utilisateur, ce n'est pas vraiment intressant. V ous imaginez un jeu o on ne fait que regarder ? a s'appelle une vido, c'est intressant aussi, mais ce n'est pas pareil ! Aujourd'hui, il existe beaucoup d'interfaces de communication que l'on peut utiliser sur un ordinateur (clavier, souris, doigts, manettes,). Dans ce chapitre nous allons regarder comment savoir ce que l'utilisateur a saisi au clavier dans une application console.

Lire une phrase


Lorsque nous lui en donnerons la possibilit, l'utilisateur de notre programme pourra saisir des choses grce son clavier. Nous pouvons lui demander son ge, s'il veut terminer notre application, lui permettre de saisir un mail, etc ... Il nous faut donc un moyen lui permettant de saisir des caractres en tapant sur son clavier. Nous pourrons faire cela grce la mthode Console.ReadLine: Code : C# string saisie = Console.ReadLine();

Lorsque notre application rencontre cette instruction, elle se met en pause et attend une saisie de la part de lutilisateur. La saisie sarrte lorsque lutilisateur valide ce quil a crit avec la touche entre. Ainsi les instructions suivantes : Code : C# Console.WriteLine("Veuillez saisir une phrase et valider avec la touche \"Entre\""); string saisie = Console.ReadLine(); Console.WriteLine("Vous avez saisi : " + saisie);

produiront :

V ous aurez remarqu que nous stockons le rsultat de la saisie dans une variable de type chaine de caractres. Cest bien souvent le seul type que nous aurons notre disposition lors des saisies utilisateurs. Cela veut bien sr dire que si vous avez

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


besoin de manipuler lge de la personne, il faudra la convertir en entier. Par exemple : Code : C# bool ageIsValid = false; int age = -1; while (!ageIsValid) { Console.WriteLine("Veuillez saisir votre age"); string saisie = Console.ReadLine(); if (int.TryParse(saisie, out age)) ageIsValid = true; else { ageIsValid = false; Console.WriteLine("L'age que vous avez saisi est incorrect ..."); } } Console.WriteLine("Votre ge est de : " + age);

105/381

Et nous aurons :

Ce code est facile comprendre maintenant que vous maitrisez les boucles et les conditions. Nous commenons par initialiser nos variables. Ensuite, nous demandons lutilisateur de saisir son ge. Nous tentons de le convertir en entier, si cela fonctionne on pourra passer la suite, sinon, tant que lge nest pas valide, nous recommenons la boucle. Il est primordial de toujours vrifier ce que saisi lutilisateur, cela vous vitera beaucoup derreurs et de plantages intempestifs de votre application. On dit souvent quen informatique, il ne faut jamais faire confiance lutilisateur.

Lire un caractre
Il peut arriver que nous ayons besoin de ne saisir quun seul caractre, pour cela nous allons pouvoir utiliser la mthode Console.ReadKey(). Nous pourrons nous en servir par exemple pour faire une pause dans notre application. Le code suivant rclame lattention de lutilisateur avant de dmarrer un calcul hautement important : Code : C#

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


Console.WriteLine("Veuillez appuyer sur une touche pour dmarrer le calcul ..."); Console.ReadKey(true); int somme = 0; for (int i = 0; i < 100; i++) { somme += i; } Console.WriteLine(somme);

106/381

Ce qui nous donnera :

noter que nous avons pass true en paramtre de la mthode afin dindiquer au C# que nous ne souhaitions pas que notre saisie apparaisse lcran. Si le paramtre avait t false et que javais par exemple appuy sur h pour dmarrer le calcul, le rsultat se serait vu prcd dun disgracieux h Dailleurs, comment faire pour savoir quelle touche a t saisie ?

Il suffit dobserver le contenu de la variable renvoye par la mthode Console.ReadKey. Elle renvoie en loccurrence une variable du type ConsoleKeyInfo. Nous pourrons comparer la valeur Key de cette variable qui est une numration du type ConsoleKey. Par exemple : Code : C# Console.WriteLine("Voulez-vous continuer (O/N) ?"); ConsoleKeyInfo saisie = Console.ReadKey(true); if (saisie.Key == ConsoleKey.O) { Console.WriteLine("On continue ..."); } else { Console.WriteLine("On s'arrte ..."); }

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


Nous remarquons grce la compltion automatique que lnumration ConsoleKey possde plein de valeur :

107/381

Nous comparons donc la valeur ConsoleKey.O qui reprsente la touche o. noter que le type ConsoleKeyInfo est ce quon appelle une structure et que Key est une proprit de la structure. Nous reviendrons dans la partie suivante sur ce que cela veut vraiment dire. Pour linstant, considrez juste quil sagit dune variable volue qui permet de contenir plusieurs choses

En rsum
La mthode Console.ReadLine nous permet de lire des informations saisies par l'utilisateur au clavier. Il est possible de lire toute une phrase termine par la touche Entre ou seulement un unique caractre.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

108/381

Utiliser le dbogueur
Nous allons maintenant faire une petite pause. Le C# c'est bien, mais notre environnement de dveloppement, Visual C# Express, peut faire beaucoup plus que sa fonction basique d'diteur de fichiers. Il possde un outil formidable qui va nous permettre d'tre trs efficaces dans le dbogage de nos applications et dans la comprhension de leur fonctionnement. Il s'agit du dbogueur. Dcouvrons vite quoi il sert et comment il fonctionne

A quoi a sert ?
Fidle son habitude de nous simplifier la vie, Visual C# express possde un dbogueur. Cest un outil trs pratique qui va permettre dobtenir plein dinformations sur le droulement de son programme. Il va permettre d'excuter les instructions les unes aprs les autres, de pouvoir observer le contenu des variables, de revenir en arrire, bref, de pouvoir savoir exactement ce quil se passe et surtout pourquoi tel bout de code ne fonctionne pas. Pour lutiliser, il faut que Visual C# express soit en mode dbogage . Je nen ai pas encore parl. Pour ce faire, il faut excuter lapplication en appuyant sur F5 ou en passant par le menu Dboguer > Dmarrer le dbogage ou en cliquant sur le petit triangle vert dont licne rappelle un bouton de lecture.

Pour tudier le dbogueur, reprenons la dernire mthode du prcdent TP : Code : C# static void Main(string[] args) { Console.WriteLine(CalculSommeIntersection()); } static int CalculSommeIntersection() { List<int> multiplesDe3 = new List<int>(); List<int> multiplesDe5 = new List<int>(); for (int i = 1; i <= 100; i++) { if (i % 3 == 0) multiplesDe3.Add(i); if (i % 5 == 0) multiplesDe5.Add(i); } int somme = 0; foreach (int m3 in multiplesDe3) { foreach (int m5 in multiplesDe5) { if (m3 == m5) somme += m3; } } return somme;

Mettre un point darrt et avancer pas pas


www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

109/381

Pour que le programme sarrte sur un endroit prcis et quil nous permette de voir ce quil se passe, il va falloir mettre des points darrts dans notre code. Pour mettre un point darrt, il faut se positionner sur la ligne o nous souhaitons nous arrter, par exemple la premire ligne o nous appelons Console.WriteLine et appuyer sur F9. Nous pouvons galement cliquer dans la marge gauche pour produire le mme rsultat. Un point rouge saffiche et indique quil y a un point darrt cet endroit.

Il est possible de mettre autant de points darrts que nous le souhaitons, nimporte quel endroit de notre code. Lanons lapplication avec F5, nous pouvons voir que Visual C# express sarrte sur la ligne prvue en la surlignant en jaune :

Nous en profitons pour remarquer au niveau du carr rouge que le dbogueur est en pause et quil est possible soit de continuer

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

110/381

lexcution (triangle) soit de larrter (carr) soit de redmarrer le programme depuis le dbut (carr avec une flche blanche dedans). Nous pouvons dsormais excuter notre code pas pas, en nous servant des icnes cot ou des raccourcis claviers suivants :

Utilisons la touche F10 pour continuer lexcution du code pas pas. La ligne suivante se trouve surligne son tour. Appuyons nouveau sur la touche F10 pour aller linstruction suivante, il ny en a plus le programme se termine. V ous me direz, cest bien beau, mais, nous ne sommes pas passs dans la mthode CalculSommeIntersection() . Et oui, cest parce que nous avons utilis la touche F10 qui est le pas pas principal. Pour rentrer dans la mthode, il aurait fallu utiliser la touche F11 qui est le pas pas dtaill. Si nous souhaitons que le programme se poursuive pour aller jusquau prochain point darrt, il suffit dappuyer sur le triangle (play) ou sur F5. Relanons notre programme en mode dbogage, et cette fois-ci, lorsque le dbogueur sarrte sur notre point darrt, appuyons sur F11 pour rentrer dans le corps de la mthode. V oil, nous sommes dans la mthode CalculSommeIntersection(). Continuons appuyer plusieurs fois sur F10 afin de rentrer dans le corps de la boucle for.

Observer des variables

ce moment-l du dbogage, si nous passons la souris sur la variable i, qui est lindice de la boucle, Visual C# express va nous afficher une mini-information :

Il nous indique que i vaut 1, ce qui est normal, nous sommes dans la premire itration de la boucle. Si nous continuons le parcours en appuyant sur F10 plusieurs fois, nous voyons que la valeur de i augmente, conformment ce qui est attendu. Maintenant, mettons un point darrt - F9 - sur la ligne : Code : C# multiplesDe3.Add(i);

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

111/381

et poursuivons lexcution en appuyant sur F5. Il sarrte au moment o i vaut 3. Appuyons sur F10 pour excuter lajout de i la liste et passons la souris sur la liste :

Visual C# express nous indique que la liste multiplesDe3 a son Count qui vaut 1. Si nous cliquons sur le + pour dplier la liste :

nous pouvons voir que 3 a t ajout dans le premier emplacement de la liste (indice 0). Si nous continuons lexcution plusieurs fois, nous voyons que les listes se remplissent au fur et mesure. Enlevez le point darrt sur la ligne en appuyant nouveau sur F9 et mettez un nouveau point darrt sur la ligne : Code : C# int somme = 0;

Poursuivez lexcution avec F5, la boucle est termine, nous pouvons voir que les listes sont compltement remplies :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

112/381

Grce au dbogueur, nous pouvons voir vraiment tout ce qui nous intresse, cest une des grandes forces du dbogueur et cest un atout vraiment trs utile pour comprendre ce quil se passe dans un programme (en gnral, a se passe mal !). Il est galement possible de voir les variables locales en regardant en bas dans la fentre Variables locales . Dans cette fentre, vous pourrez observer les variables qui sont dans la porte courante. Il existe galement une fentre Espion qui permet de la mme faon de surveiller une ou plusieurs variables prcises.

Revenir en arrire
Nom de Zeus, Marty ! On peut revenir dans le pass ?

Cest presque a Doc ! Si pour une raison, vous souhaitez r-excuter un bout de code, parce que vous navez pas bien vu ou que vous avez rat linformation quil vous fallait, vous pouvez forcer le dbogueur revenir en arrire dans le programme. Pour cela, vous avez deux solutions, soit vous faites un clic droit lendroit souhait et vous choisissez llment de menu Dfinir linstruction suivante :

soit vous dplacez avec la souris la petite flche jaune sur la gauche qui indique lendroit o nous en sommes.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

113/381

Il faut faire attention car ce retour en arrire nen est pas compltement un. En effet, si vous revenez au dbut de la boucle qui calcule les multiples et que vous continuez lexcution, vous verrez que la liste continue se remplir. la fin de la boucle, au lieu de contenir 33 lments, la liste des multiples de 3 en contiendra 66. En effet, aucun moment nous n'avons vid la liste et donc le fait de r-excuter cette partie de code risque de provoquer des comportements inattendus. Ici, il vaudrait mieux revenir au dbut de la mthode afin que la liste soit de nouveau cre. Mme si a ne vous saute pas aux yeux pour linstant, vous verrez lusage que cette possibilit est bien pratique. Dautant plus quand vous aurez bien assimil toutes les notions de porte de variable. Il est important de noter que, bien que puissant, le dbogueur de la version gratuite de Visual Studio est vraiment moins puissant que celui des versions payantes. Il y a plein de choses en moins que lon ne peut pas faire. Mais rassurez-vous, celui-ci est quand mme dj bien avanc et permet de faire beaucoup de choses.

La pile des appels


Une autre fentre importante regarder est la pile des appels, elle permet dindiquer o nous nous trouvons et par o nous sommes passs pour arriver cet endroit-l. Par exemple si vous appuyez sur F11 et que vous rentrez dans la mthode CalculSommeIntersection() vous pourrez voir dans la pile des appels que vous tes dans la mthode CalculSommeIntersection() qui a t appele depuis la mthode Main() :

Si vous cliquez sur la ligne du Main(), Visual C# express vous ramne automatiquement lendroit o a t fait lappel. Cette ligne est alors surligne en vert pour bien faire la diffrence avec le surlignage en jaune qui est vraiment lendroit o se trouve le dbogueur. Cest trs pratique quand on a beaucoup de mthodes qui sappellent les unes la suite des autres.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

114/381

La pile des appels est galement affiche lorsquon rencontre une erreur, elle permettra didentifier plus facilement o est le problme. V ous l'avez vu dans le chapitre sur les conversions entre les types incompatibles.

En tous cas, le dbogueur est vraiment un outil forte valeur ajoute. Je ne vous ai prsent que le strict minimum ncessaire et indispensable. Mais croyez-moi, vous aurez loccasion dy revenir .

En rsum
Le dbogueur est un outil trs puissant permettant d'inspecter le contenu des variables lors de l'excution d'un programme. On peut s'arrter un endroit de notre application grce un point d'arrt. Le dbogueur permet d'excuter son application pas pas et de suivre son volution.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

115/381

TP : le jeu du plus ou du moins


Wahou, nous augmentons rgulirement le nombre de choses que nous savons. C'est super. Nous commenons tre capables d'crire des applications qui ont un peu plus de panache ! Enfin moi, j'y arrive ! Et vous ? C'est ce que nous allons vrifier avec ce TP. Savoir interagir avec son utilisateur est important. V donc un petit TP sous forme de cration d'un jeu simple qui va vous oici permettre de vous entraner. L'ide est de raliser le jeu classique du plus ou du moins

Instructions pour raliser le TP


Je vous rappelle les rgles. Lordinateur nous calcule un nombre alatoire et nous devons le deviner. chaque saisie, il nous indique si le nombre saisi est plus grand ou plus petit que le nombre trouver. Une fois trouv, il nous indique en combien de coups nous avons russi trouver le nombre secret. Pour ce TP, vous savez presque tout faire. Il ne vous manque que linstruction pour obtenir un nombre alatoire. La voici, cette instruction permet de renvoyer un nombre compris entre 0 et 100 (exclu). Ne vous attardez pas trop sur sa syntaxe, nous aurons loccasion de comprendre exactement de quoi il sagit dans le chapitre suivant : Code : C# int valeurATrouver = new Random().Next(0, 100);

Le principe est grosso modo le suivant : tant quon na pas trouv la bonne valeur, nous devons en saisir une nouvelle. Dans ce cas, la console nous indique si la valeur est trop grande ou trop petite. Il faudra bien sur incrmenter un compteur de coups chaque essai. Noubliez pas de grer le cas o lutilisateur saisit nimporte quoi. Nous ne voudrions pas que notre premier jeu ait un bug qui fasse planter lapplication ! Allez, je vous en ai trop dit. Cest vous de jouer. Bon courage.

Correction
V ma correction de ce TP. oici Bien sr, il existe beaucoup de faon de raliser ce petit jeu. Sil fonctionne, cest que votre solution est bonne. Ma solution fonctionne, la voici : Code : C# static void Main(string[] args) { int valeurATrouver = new Random().Next(0, 100); int nombreDeCoups = 0; bool trouve = false; Console.WriteLine("Veuillez saisir un nombre compris entre 0 et 100 (exclu)"); while (!trouve) { string saisie = Console.ReadLine(); int valeurSaisie; if (int.TryParse(saisie, out valeurSaisie)) { if (valeurSaisie == valeurATrouver) trouve = true; else { if (valeurSaisie < valeurATrouver) Console.WriteLine("Trop petit ..."); else Console.WriteLine("Trop grand ..."); } nombreDeCoups++; }

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


Console.WriteLine("La valeur saisie est incorrecte, veuillez recommencer ..."); } Console.WriteLine("Vous avez trouv en " + nombreDeCoups + " coup(s)"); } else

116/381

On commence par obtenir un nombre alatoire avec linstruction que jai fournie dans lnonc. Nous avons ensuite les initialisations de variables. Lentier nombreDeCoups va permettre de stocker le nombre dessai et le boolen trouve va permettre davoir une condition de sortie de boucle. Notre boucle dmarre et ne se terminera quune fois que le boolen trouve sera pass vrai (true). Dans le corps de la boucle, nous demandons lutilisateur de saisir une valeur que nous essayons de convertir en entier. Si la conversion choue, nous lindiquons lutilisateur et nous recommenons notre boucle. Notez ici que je nincrmente pas le nombre de coups, jugeant quil ny a pas lieu de pnaliser le joueur parce quil a mal saisi ou quil a renvers quelque chose sur son clavier juste avant de valider la saisie. Si par contre la conversion se passe bien, nous pouvons commencer comparer la valeur saisie avec la valeur trouver. Si la valeur est la bonne, nous passons le boolen vrai, ce qui nous permettra de sortir de la boucle et de passer la suite. Sinon, nous afficherons un message pour indiquer si la saisie est trop grande ou trop petite en fonction du rsultat de la comparaison. Dans tous les cas, nous incrmenterons le nombre de coups. Enfin, en sortie de boucle, nous indiquerons sa victoire au joueur ainsi que le nombre de coups utiliss pour trouver le nombre secret. Une partie de jeu pourra tre :

Aller plus loin


Il est bien sr toujours possible damliorer le jeu. Nous pourrions par exemple ajouter un contrle sur les bornes de la saisie. Ainsi, si lutilisateur saisit un nombre suprieur ou gal 100 ou infrieur 0, nous pourrions lui rappeler les bornes du nombre alatoire. De mme, la fin, plutt que dafficher coup(s) , nous pourrions tester la valeur du nombre de coups. Sil est gal 1, on affiche coup au singulier, sinon coups au pluriel. La boucle pourrait galement tre lgrement diffrente. Plutt que de tester la condition de sortie sur un boolen, nous pourrions utiliser le mot cl break. De mme, nous pourrions allger lcriture avec le mot cl continue. Par exemple :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


Code : C# static void Main(string[] args) { int valeurATrouver = new Random().Next(0, 100); int nombreDeCoups = 0; Console.WriteLine("Veuillez saisir un nombre compris entre 0 100 (exclu)"); while (true) { string saisie = Console.ReadLine(); int valeurSaisie; if (!int.TryParse(saisie, out valeurSaisie)) { Console.WriteLine("La valeur saisie est incorrecte, veuillez recommencer ..."); continue; } if (valeurSaisie < 0 || valeurSaisie >= 100) { Console.WriteLine("Vous devez saisir un nombre entre et 100 exclu ..."); continue; } nombreDeCoups++; if (valeurSaisie == valeurATrouver) break; if (valeurSaisie < valeurATrouver) Console.WriteLine("Trop petit ..."); else Console.WriteLine("Trop grand ..."); } if (nombreDeCoups == 1) Console.WriteLine("Vous avez trouv en " + nombreDeCoups coup"); else Console.WriteLine("Vous avez trouv en " + nombreDeCoups coups"); }

117/381

et

+ " + "

Tout ceci est une question de got. Je prfre personnellement la version prcdente naimant pas trop les break et les continue. Mais aprs tout, chacun fait comme il prfre, limportant est que nous amusions crire le programme et y jouer. V oil, ce TP est termin. V ous avez pu voir finalement que nous tions tout fait capables de raliser des petites applications rcratives. Personnellement, j'ai commenc m'amuser faire de la programmation en ralisant toute sorte de petits programmes de ce genre. Je vous encourage fortement essayer de crer d'autres programmes vous-mmes, pourquoi pas proposer aux autres vos ides. Plus vous vous entranerez faire des petits programmes simples et plus vous russirez apprhender les subtilits de ce que nous avons appris. Bien sr, plus tard, nous serons capables de raliser des applications plus compliques ... Cela vous tente ? Alors continuons la lecture.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

118/381

La ligne de commande
Sous ce nom un peu barbare se cache une fonctionnalit trs prsente dans nos usages quotidiens mais qui a tendance tre masque l'utilisateur lambda. Nous allons, dans un premier temps, voir ce qu'est exactement la ligne de commande et quoi elle sert. Ensuite, nous verrons comment l'exploiter dans notre application avec le C#. Notez que ce chapitre n'est pas essentiel mais qu'il pourra srement vous servir plus tard dans la cration de vos applications.

Quest-ce que la ligne de commande ?


La ligne de commande, cest ce qui nous permet dexcuter nos programmes. Trs prsente lpoque o Windows existait peu, elle a tendance disparaitre de nos utilisations. Mais pas le fond de son fonctionnement. En gnral, la ligne de commande sert passer des arguments un programme. Par exemple, pour ouvrir un fichier texte avec le bloc-notes (notepad.exe), on peut le faire de deux faons diffrentes. Soit on ouvre le bloc-notes et on va dans le menu Fichier > Ouvrir puis on va chercher le fichier pour louvrir. Soit on utilise la ligne de commande pour louvrir directement. Pour ce faire, il suffit dutiliser la commande : Code : Console notepad c:\test.txt

et le fichier c:\test.txt souvre directement dans le bloc-notes. Ce quil sest pass derrire, cest que nous avons demand dexcuter le programme notepad.exe avec le paramtre c:\test.txt. Le programme notepad a analys sa ligne de commande, il y a trouv un paramtre et il a ouvert le fichier correspondant. Superbe ! Nous allons apprendre faire pareil !

Passer des paramtres en ligne de commande


La premire chose faire est de savoir comment faire pour passer des paramtres en ligne de commande. Plusieurs solutions existent. On peut par exemple excuter la commande que jai crite plus haut depuis le menu Dmarrer > Excuter (ou la combinaison windows + r).

On peut galement le faire depuis une invite de commande (Menu Dmarrer > Accessoires > Invite de commande) :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

119/381

Ceci nous ouvre une console noire, comme celle que lon connait bien et dans laquelle nous pouvons taper des instructions :

Mais nous, ce qui nous intresse surtout, cest de pouvoir le faire depuis Visual C# Express afin de pouvoir passer des arguments notre programme. Pour ce faire, on va aller dans les proprits de notre projet (bouton droit sur le projet, Proprits) puis nous allons dans longlet Dboguer et nous voyons une zone de texte permettant de mettre des arguments la ligne de commande. Rajoutons par exemple Bonjour Nico :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

120/381

V oil, maintenant lorsque nous excuterons notre application, Visual C# express lui passera les arguments que nous avons dfinis en paramtre de la ligne de commande. A noter que dans ce cas, les arguments Bonjour Nico ne seront valables que lorsque nous excuterons lapplication travers Visual C# express. Evidemment, si nous excutons notre application par linvite de commande, nous aurons besoin de repasser les arguments au programme pour quil puisse les exploiter. Cest bien ! Sauf que pour linstant, a ne nous change pas la vie ! Il faut apprendre traiter ces paramtres

Lire la ligne de commande


On peut lire le contenu de la ligne de commande de deux faons diffrentes. V ous vous rappelez de la mthode Main() ? On a vu que Visual C# express gnrait cette mthode avec des paramtres. Et bien ces paramtres, vous ne devinerez jamais ! Ce sont les paramtres de la ligne de commande. Oh joie ! Code : C# static void Main(string[] args) { }

La variable args est un tableau de chaine de caractres. Sachant que chaque paramtre est dlimit par des espaces, nous retrouverons chacun des paramtres un indice du tableau diffrent. Ce qui fait que si jutilise le code suivant : Code : C# foreach (string parametre in args) { Console.WriteLine(parametre); }

et que je lance mon application avec les paramtres dfinis prcdemment, je vais obtenir :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

121/381

Et voil, nous avons rcupr les paramtres de la ligne de commande, il ne nous restera plus qu les traiter dans notre programme. Comme prvu, nous obtenons deux paramtres. Le premier est la chaine de caractres Bonjour , le deuxime est la chaine de caractres Nico . Noubliez pas que cest le caractre despacement qui sert de dlimiteur entre les paramtres. Lautre faon de rcuprer la ligne de commande est dutiliser la mthode Environment.GetCommandLineArgs(). Elle renvoie un tableau contenant les paramtres, comme ce qui est pass en paramtres la mthode Main. La seule diffrence, cest que dans le premier lment du tableau, nous trouverons le chemin complet de notre programme. Ceci peut tre utile dans certains cas. Si cela na aucun intrt pour vous, il suffira de commencer la lecture partir de lindice numro 1. Lexemple suivant affiche toutes les valeurs du tableau : Code : C# foreach (string parametre in Environment.GetCommandLineArgs()) { Console.WriteLine(parametre); }

Ce qui donne :

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

122/381

Attention : si vous devez accder un indice prcis du tableau, vrifiez bien que la taille du tableau le permet. Noubliez pas que si le tableau contient un seul lment et que vous essayez daccder au deuxime lment, alors il y aura une erreur.

Tu as dit que ctait le caractre despacement qui permettait de dlimiter les paramtres. Jai essay de rajouter le paramtre C:\Program Files\test.txt ma ligne de commande afin de changer lemplacement du fichier, mais je me retrouve avec deux paramtres au lieu dun seul, c'est normal ?

Eh oui, il y a un espace entre Program et Files. Lastuce est de passer le paramtre entre guillemets, de cette faon : "C:\Program Files\test.txt". Nous aurons un seul paramtre dans la ligne de commande la place de 2. Comme par exemple :

En rsum
On peut passer des paramtres une application en utilisant la ligne de commande. Le programme C# peut lire et interprter ces paramtres. Ces paramtres sont spars par des espaces.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#

123/381

TP : Calculs en ligne de commande


Et voici un nouveau TP qui va nous permettre de rcapituler un peu tout ce que nous avons vu. Au programme, des if, des switch, des mthodes, des boucles et... de la ligne de commande bien sr ! Grce nos connaissances grandissantes, nous arrivons augmenter la difficult de nos exercices et c'est une bonne chose. V ous verrez que dans le moindre petit programme, vous aurez besoin de toutes les notions que nous avons apprises. Allez, ne tranons pas trop et vous de jouer travailler.

Instructions pour raliser le TP


Lobjectif de ce TP est de raliser un petit programme qui permet deffectuer une opration mathmatique partir de la ligne de commande. Il va donc falloir crire un programme que l'on pourra appeler avec des paramtres. En imaginant que le programme s'appelle MonProgramme , on pourrait l'utiliser ainsi pour faire la somme de deux nombres : MonProgramme somme 2 5 Ce qui renverra bien sr 7. Pour effectuer une multiplication, nous pourrons faire : MonProgramme multiplication 2 5 et nous obtiendrons 10. Enfin, pour calculer une moyenne, nous pourrons faire : MonProgramme moyenne 1 2 3 4 5 ce qui renverra 3. Les rgles sont les suivantes : Il doit y avoir 2 et seulement 2 nombres composant laddition et la multiplication La moyenne peut contenir autant de nombres que souhait Si le nombre de paramtres est incorrect, alors le programme affichera un message daide explicite Si le nombre attendu nest pas un double correct, on affichera le message daide Plutt simple non ? Alors, vous de jouer, il ny a pas de subtilit.

Correction
STOP. Je relve les copies. Jai dit quil ny avait pas de subtilit, mais jai un peu menti en fait. Javoue, ctait pour que vous alliez au bout du dveloppement sans aide. Pour vrifier que vous avez trouv la subtilit, essayez votre programme avec les paramtres suivants : MonProgramme addition 5,5 2,5 Obtenez-vous 8 ?

Ctait peu prs la seule subtilit, il fallait juste savoir quun nombre virgule scrivait avec une virgule plutt quavec un point. Si nous crivons 2.5, alors le C# ne sait pas faire la conversion. En vrai, cest un peu plus compliqu que a et nous le verrons dans un prochain chapitre, mais lcriture du nombre virgule est dpendant de ce quon appelle la culture courante que lon peut modifier dans les paramtres horloge, langue et rgion du panneau de configuration de Windows. Si lon change le format de la date, de lheure ou des nombres on change la culture courante, et la faon dont les nombres virgules (et autres) sont grs est diffrente. Nous en reparlerons plus prcisment dans un chapitre ultrieur.

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


Quoiqu'il en soit, voici ma correction du TP : Code : C# static void Main(string[] args) { if (args.Length == 0) { AfficherAide(); } else { string operateur = args[0]; switch (operateur) { case "addition": Addition(args); break; case "multiplication": Multiplication(args); break; case "moyenne": Moyenne(args); break; default: AfficherAide(); break; } } } static void AfficherAide() { Console.WriteLine("Utilisez l'application de la manire suivante :"); Console.WriteLine("MonProgamme addition 2 5"); Console.WriteLine("MonProgamme multiplication 2 5"); Console.WriteLine("MonProgamme moyenne 2 5 10 11"); } static void Addition(string[] args) { if (args.Length != 3) { AfficherAide(); } else { double somme = 0; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) { AfficherAide(); return; } somme += valeur; } Console.WriteLine("Rsultat de l'addition : " + somme); } } static void Multiplication(string[] args) { if (args.Length != 3) { AfficherAide();

124/381

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


} else {

125/381

double resultat = 1; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) { AfficherAide(); return; } resultat *= valeur; } Console.WriteLine("Rsultat de la multiplication : " + resultat); } } static void Moyenne(string[] args) { double total = 0; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) { AfficherAide(); return; } total += valeur; } total = total / (args.Length - 1); Console.WriteLine("Rsultat de la moyenne : " + total); }

Disons que cest plus long que difficile... Oui je sais, lors de laddition et de la multiplication, jai parcouru lensemble des paramtres alors que jaurais pu utiliser uniquement args[1] et args[2]. Lavantage cest que si je supprime la condition sur le nombre de paramtres, alors mon addition pourra fonctionner avec autant de nombres que je le souhaite V ous aurez remarqu que je commence mon parcours lindice 1, do la pertinence de lutilisation de la boucle for plutt que la boucle foreach. Notez quand mme lutilisation du mot cl return afin de sortir prmaturment de la mthode en cas de problme. videmment, il y a plein de faons de raliser ce TP, la mienne en est une, il y en a d'autres. Jespre que vous aurez fait attention au calcul de la moyenne. Nous retirons 1 la longueur du tableau pour obtenir le nombre de paramtres. Il faut donc faire attention lordre des parenthses afin que le C# fasse d'abord la soustraction avant la division, alors que sans a, la division est prioritaire la soustraction. Sinon, c'est l'erreur de calcul assure, indigne de notre superbe application.

Aller plus loin


Ce code est trs bien. Sisi, c'est moi qui l'ai fait .

Sauf qu'il y a quand mme un petit problme ... d'ordre architectural. Il a t plutt simple crire en suivant l'nonc du TP mais on peut faire encore mieux. On peut le rendre plus facilement maintenable en le r-architecturant diffremment. Observez le code suivant : Code : C#

www.siteduzero.com

Partie 2 : Un peu plus loin avec le C#


static void Main(string[] args) { bool ok = false; if (args.Length > 0) { string operateur = args[0]; switch (operateur) { case "addition": ok = Addition(args); break; case "multiplication": ok = Multiplication(args); break; case "moyenne": ok = Moyenne(args); break; } } if (!ok) AfficherAide();

126/381

static void AfficherAide() { Console.WriteLine("Utilisez l'application de la manire suivante :"); Console.WriteLine("MonProgamme addition 2 5"); Console.WriteLine("MonProgamme multiplication 2 5"); Console.WriteLine("MonProgamme moyenne 2 5 10 11"); } static bool Addition(string[] args) { if (args.Length != 3) return false; double somme = 0; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) return false; somme += valeur; } Console.WriteLine("Rsultat de l'addition : " + somme); return true;

static bool Multiplication(string[] args) { if (args.Length != 3) return false; double resultat = 1; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) return false; resultat *= valeur; } Console.WriteLine("Rsultat de la multiplication : " + resultat); return true; } static bool Moyenne(string[] args)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ double total = 0; for (int i = 1; i < args.Length; i++) { double valeur; if (!double.TryParse(args[i], out valeur)) return false; total += valeur; } total = total / (args.Length - 1); Console.WriteLine("Rsultat de la moyenne : " + total); return true;

127/381

Nous n'affichons l'aide plus qu' un seul endroit en utilisant le fait que les mthodes renvoient un boolen indiquant si l'opration a t possible ou pas. D'une manire gnrale, il est important d'essayer de rendre son code le plus maintenable possible, comme nous l'avons fait ici. V oil, j'espre que vous aurez russi ce TP. V ous pouvez bien sr complter notre calculatrice lmentaire en y rajoutant des notions plus compliques, comme la racine carre ou la mise la puissance. ce propos, comme les mthodes Math.Sqrt() ou Math.Pow(), il existe de nombreuses mthodes permettant de faire des oprations de toutes sortes. V ous pouvez les consulter cette adresse dans la documentation en ligne. (oui, je suis d'accord, ce n'est pas tous les jours que nous aurons envie de calculer la tangente hyperbolique d'un angle ... mais sait-on jamais ). En tous cas, n'hsitez pas faire des variations sur les diffrents TP que je vous ai proposs, il est toujours intressant de sortir des sentiers battus. V pour cette partie. oil Non, nous ne savons pas encore tout, loin de l !

Nous avons simplement continu plonger dans les bases du C#. Grce cette partie, vous avez pu commencer faire des programmes un peu plus rigolos en lisant les saisies utilisateurs partir du clavier. V ous avez galement pu mettre un premier pas dans le monde trs important des conversions entre les types. Bien sr, vous devez imprativement essayer d'en crer d'autres. Plus vous pratiquerez et plus vous deviendrez l'aise avec les diffrents concepts. N'hsitez pas chercher des informations dans la documentation en ligne si besoin. Il y a beaucoup de ressources sur internet, votre curiosit pourrait vous amener dcouvrir des bonnes surprises... Dans la prochaine partie, nous continuerons tudier la syntaxe du C# et nous dcouvrirons le C# comme un langage orient objet. C'est une trs vaste partie avec pas mal de thorie. Alors ds prsent, armez vous de courage et noubliez pas de faire des pauses .

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

128/381

Partie 3 : Le C#, un langage orient objet


Bienvenue dans cette nouvelle partie. Dans les prcdentes, vous avez pu dcouvrir les bases du C#. Nous avons vu beaucoup de choses, mais finalement, nous avons volontairement clips une trs grosse notion lie au dveloppement en C#, savoir que le C# est un langage orient objet. Dans cette partie, nous allons dcouvrir ce quest lorient objet puis nous allons voir comment utiliser le C# dans cette optique. Il est important avant de continuer davoir bien compris le dbut du tutoriel et de stre entran afin de ne pas se laisser drouter par les notions que nous avons vues et de se concentrer sur lessentiel de cette partie. Bon courage et bonne lecture .

Introduction la programmation oriente objet


Dans ce chapitre, nous allons essayer de dcrire ce qu'est la programmation oriente objet (abrge souvent en POO). Je dis bien essayer , car pour tre compltement traite, la POO ncessiterait qu'on lui ddie un ouvrage entier ! Nous allons tcher d'aller l'essentiel et de rester proche de la pratique. Ce n'est pas trs grave si tous les concepts abstraits ne sont pas parfaitement apprhends : il est impossible d'apprendre la POO en deux heures. Cela ncessite une longue pratique, beaucoup d'empirisme et des approfondissements thoriques. Ce qui est important ici, c'est de comprendre les notions de base et de pouvoir les utiliser dans de petits programmes. Aprs cette mise au point, attaquons sans plus tarder la programmation oriente objet !

Qu'est-ce qu'un objet ?


V ous avez pu voir prcdemment que jai utilis de temps en temps le mot objet et que le mot-cl new est apparu comme par magie Il a t difficile de ne pas trop en parler et il est temps den savoir un peu plus. Alors quest-ce quun objet ? Si on prend le monde rel (si si, vous allez voir, vous connaissez), nous sommes entours dobjets : une chaise, une table, une voiture, etc. Ces objets forment un tout. Ils possdent des proprits (la chaise possde 4 pieds, elle est de couleur bleue, etc.). Ces objets peuvent faire des actions (la voiture peut rouler, klaxonner, etc.). Ils peuvent galement interagir entre eux (lobjet conducteur dmarre la voiture, lobjet voiture fait tourner lobjet volant, etc.).

Il faut bien faire attention distinguer ce quest lobjet et ce qu'est la dfinition dun objet La dfinition de lobjet (ou structure de lobjet) permet dindiquer ce qui compose un objet, c'est--dire quelles sont ses proprits, ses actions etc. Comme par exemple le fait quune chaise ait des pieds ou quon puisse sasseoir dessus. Par contre, lobjet chaise est bien concret. On peut donc avoir plusieurs objets chaises : on parle galement dinstances. Les objets chaises, ce sont bien celles concrtes que lon voit devant nous autour de lobjet table pour dmarrer une partie de belote. On peut faire lanalogie avec notre dictionnaire qui nous dcrit ce quest une chaise. Le dictionnaire dcrit en quoi consiste lobjet, et linstance de lobjet reprsente le concret associ cette dfinition. Chaque objet a sa propre vie et est diffrent dun autre. Nous pouvons avoir une chaise bleue, une autre rouge, une autre avec des roulettes, une casse Bon, finalement la notion dobjet est plutt simple quand on la ramne ce quon connait dj .

Sachant quun objet en programmation cest comme un objet du monde rel mais ce nest pas forcment restreint au matriel. Un chien est un objet. Des concepts comme lamour ou une ide sont galement des objets, tandis quon ne dirait pas cela dans le monde rel. En conclusion : La dfinition (ou structure) dun objet est un concept abstrait, comme une dfinition dans le dictionnaire. Cette dfinition dcrit les caractristiques dun objet (la chaise a des pieds, lhomme a des jambes, etc.). Cette dfinition est unique comme une dfinition dans le dictionnaire.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

129/381

Un objet ou une instance est la ralisation concrte de la structure de lobjet. On peut avoir de multiples instances, comme les 100 voitures sur le parking devant chez moi. Elles peuvent avoir des caractristiques diffrentes (une voiture bleue, une voiture lectrique, une voiture 5 portes, etc.)

Lencapsulation
Le fait de concevoir une application comme un systme dobjets interagissant entre eux apporte une certaine souplesse et une forte abstraction. Prenons un exemple tout simple : la machine caf du bureau. Nous insrons nos pices dans le monnayeur, choisissons la boisson et nous nous retrouvons avec un gobelet de la boisson commande. Nous nous moquons compltement de savoir comment cela fonctionne lintrieur et nous pouvons compltement ignorer si le caf est en poudre, en grain, comment leau est ajoute, chauffe, comment le sucre est distribu, etc. Tout ce qui nous importe cest que le fait de mettre des sous dans la machine nous permet dobtenir un caf qui va nous permettre dattaquer la journe. V un bel exemple de programmation oriente objet. Nous manipulons un objet MachineACafe qui a des proprits oil (Allume/teinte, prsence de caf, prsence de gobelet, ) et qui sait faire des actions (AccepterMonnaie, DonnerCafe, ). Et cest tout ce que nous avons besoin de savoir. On se moque du fonctionnement interne, peu importe ce quil se passe lintrieur, notre objet nous donne du caf, point ! Cest ce quon appelle lencapsulation. Cela permet de protger linformation contenue dans notre objet et de le rendre manipulable uniquement par ses actions ou proprits. Ainsi, lutilisateur ne peut pas accder au caf ni au sucre ou encore moins la monnaie. Notre objet est ainsi protg et fonctionne un peu comme une boite noire. Lintrt est que si la personne qui entretient la machine met du caf en grain la place du caf soluble, cest invisible pour lutilisateur qui se soucie simplement de mettre ses pices dans la machine. Lencapsulation protge donc les donnes de lobjet et son fonctionnement interne.

Hritage
Un autre lment important dans la programmation oriente objet que nous allons aborder est lhritage. Ah bon ? Les objets aussi peuvent mourir et transmettre leur patrimoine ?

Eh bien cest presque comme en droit, part que lobjet ne meurt pas et quil ny pas de taxe sur lhritage. Cest--dire quun objet dit pre peut transmettre certaines de ses caractristiques un autre objet dit fils . Pour cela, on pourra dfinir une relation dhritage entre eux. Sil y a une relation dhritage entre un objet pre et un objet fils, alors lobjet fils hrite de lobjet pre. On dit galement que lobjet fils est une spcialisation de lobjet pre ou quil drive de lobjet pre. En langage plus courant on peut galement dire que lobjet fils est une sorte dobjet pre. Des exemples !!

On dit souvent quun petit exemple vaut bien un long discours, alors prenons par exemple lobjet chien et imaginons ses caractristiques tires du monde rel en utilisant lhritage : Lobjet chien est une sorte dobjet mammifre Lobjet mammifre est une sorte dobjet animal Lobjet animal est une sorte dobjet tre vivant

Chaque pre est un peu plus gnral que son fils. Et inversement, chaque fils est un peu plus spcialis que son pre. Avec lexemple du dessus, un mammifre est un peu plus gnral quun chien, ltre vivant tant encore plus gnral quun mammifre. Il est possible pour un pre davoir plusieurs fils, par contre, linverse est impossible, un fils ne peut pas avoir plusieurs pres. Et

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


oui, cest triste mais cest comme a, cest le rgne du pre clibataire avec plusieurs enfants charge !

130/381

Ainsi, un objet chat peut galement tre un fils de lobjet mammifre . Un objet vgtal peut galement tre fils de lobjet tre vivant . Ce quon peut reproduire sur le schma suivant. Chaque bulle reprsentant un objet et chaque flche reprsente lhritage entre les objets.

On peut dfinir une sorte de hirarchie entre les objets, un peu comme on le ferait avec un arbre gnalogique. La diffrence est quun objet hritant dun autre peut obtenir certains ou tous les comportements de lobjet quil spcialise, alors quun petit enfant nhrite pas forcment des yeux bleus de sa mre ou du ct bougon de son grand-pre, le hasard de la nature faisant le reste. Pour bien comprendre cet hritage de comportement, empruntons nouveau les exemples du monde rel. Ltre vivant peut par exemple faire laction vivre . Le mammifre possde des yeux. Le chien, qui est une sorte dtre vivant et une sorte de mammifre, peut galement faire laction vivre et aura des yeux. Le chat qui est une autre sorte dtre vivant peut lui aussi faire laction vivre et aura galement des yeux.

On voit bien ici que le chat et le chien hritent des comportements de leurs parents et grands-parents en tant capables de vivre et davoir des yeux. Par contre, laction aboyer est spcifique au chien. Ce qui veut dire que ni le chat, ni le dauphin ne seront capables daboyer. Il ny a que dans les dessins anims de Tex Avery que ceci est possible ! videmment, il ny a pas de notion dhritage entre le chien et le chat et laction aboyer est dfinie au niveau du comportement du chien. Ceci implique galement que seul un objet qui est une sorte de chien, par exemple lobjet Labrador ou lobjet Chihuahua, pourra hriter du comportement aboyer , car il y a une relation dhritage entre eux. Finalement, c'est plutt logique. Rappelons juste avant de terminer ce paragraphe quun objet ne peut pas hriter de plusieurs objets. Il ne peut hriter que dun seul objet. Le C# ne permet pas ce quon appelle lhritage multiple, a contrario dautres langages comme le C++ par exemple. V globalement pour la notion dhritage. Je dis globalement car il y a certaines subtilits que je nai pas abordes mais ce oil nest pas trop grave, vous verrez dans les chapitres suivants comment le C# utilise la notion dhritage et ce quil y a vraiment besoin de savoir. Ne vous inquitez pas si certaines notions sont encore un peu floues, vous comprendrez surement mieux grce la pratique.

Polymorphisme - Substitution
www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

131/381

Polymorphisme
Le mot polymorphisme suggre quune chose peut prendre plusieurs formes. Sous ce terme un peu barbare se cachent plusieurs notions de lorient objet qui sont souvent sources derreurs. Je vais volontairement passer rapidement sur certains points qui ne vont pas nous servir pour me concentrer sur ceux qui sont importants pour ce tutoriel. Jespre que vous ne men voudrez pas et que vous maccorderez quelques drogations qui pourraient dplaire aux puristes. En fait, on peut dire quune manifestation du polymorphisme est la capacit pour un objet de faire une mme action avec diffrents types dintervenants. Cest ce quon appelle le polymorphisme ad hoc ou le polymorphisme paramtr . Par exemple, notre objet voiture peut rouler sur la route, rouler sur lautoroute, rouler sur la terre si elle est quipe de pneus adquats, rouler au fond de leau si elle est amphibie, etc Concrtement ici, je fais interagir un objet voiture avec un objet autoroute ou un objet terre par laction qui consiste rouler . Cela peut paraitre anodin dcrit ainsi, mais nous verrons ce que cela implique avec le C#.

Substitution
La substitution est une autre manifestation du polymorphisme. Pas de rgime ou de balance dans ce terme-l, il sagit simplement de la capacit dun objet fils redfinir des caractristiques ou des actions dun objet pre. Prenons par exemple un objet mammifre qui sait faire laction se dplacer . Les objets qui drivent du mammifre peuvent potentiellement avoir se dplacer dune manire diffrente. Par exemple, lobjet homme va se dplacer sur ses deux jambes et donc diffremment de lobjet dauphin qui se dplacera grce ses nageoires ou bien encore diffremment de lobjet homme accident qui va avoir besoin de bquilles pour saider dans son dplacement. Tous ces mammifres sont capables de se dplacer, mais chacun va le faire dune manire diffrente. Ceci est donc possible grce la substitution qui permet de redfinir un comportement hrit. Ainsi, chaque fils sera libre de rcrire son propre comportement, si celui de son pre ne lui convient pas.

Interfaces
Un autre concept important de la programmation oriente objet est la notion dinterface. Linterface est un contrat que sengage respecter un objet. Il indique en gnral un comportement.

Prenons un exemple dans notre monde rel et connu : les prises de courant. Elles fournissent de llectricit 220V avec deux trous et (souvent) une prise de terre. Peu importe ce quil y a derrire, du courant alternatif de la centrale du coin, un transformateur, quelqu'un qui pdale,... nous saurons coup sr que nous pouvons brancher nos appareils lectriques car ces prises sengagent nous fournir du courant alternatif avec le branchement adquat. Elles respectent le contrat ; elles sont branchables . Ce dernier terme est un peu barbare et peut faire mal aux oreilles. Mais vous verrez que suffixer des interfaces par un able est trs courant ( ) et permet dtre plus prcis sur la smantique de linterface. Able est galement un suffixe qui fonctionne en anglais et les interfaces du framework .NET finissent pour la plupart par able . noter que les interfaces ne fournissent quun contrat, elles ne fournissent pas dimplmentation c'est--dire pas de code C#. Les interfaces indiquent que les objets qui choisissent de respecter ce contrat auront forcment telle action ou telle caractristique mais elles nindiquent pas comment faire, c'est--dire quelles nont pas de code C# associ. Chaque objet respectant cette interface (on parle dobjet implmentant une interface) sera responsable de coder la fonctionnalit associe au contrat. Pour manipuler ces prises, nous pourrons utiliser cette interface en disant : allez hop, tous les branchables, venez par ici, on a besoin de votre courant . Peu importe que lobjet implmentant cette interface soit une prise murale, une prise relie une dynamo ou autre, nous pourrons manipuler ces objets par leur interface et donc brancher nos prises permettant dalimenter nos appareils. Contrairement lhritage, un objet est capable dimplmenter plusieurs interfaces. Par exemple, une pompe chaleur peut tre Chauffante et Refroidissante . Notez quen franais, nous pourrons galement utiliser le suffixe ante . En anglais, nous aurons plus souvent able . Nous en avons termin avec la thorie sur les interfaces. Il est fort probable que vous ne saisissiez pas encore tout lintrt des interfaces ou ce quelles sont exactement. Nous allons y revenir avec des exemples concrets et vous verrez des utilisations des interfaces dans le cadre du framework .NET qui vous claireront d'avantage.

quoi sert la programmation oriente objet ?


Nous avons dcrit plusieurs concepts de la programmation oriente objet mais nous navons pas encore dit quoi elle allait nous servir.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

132/381

En fait, on peut dire que la POO est une faon de dvelopper une application qui consiste reprsenter (on dit galement modliser ) une application informatique sous la forme dobjets, ayant des proprits et pouvant interagir entre eux. La modlisation oriente objet est proche de la ralit ce qui fait quil sera relativement facile de modliser une application de cette faon. De plus, les personnes non-techniques pourront comprendre et ventuellement participer cette modlisation. Cette faon de modliser les choses permet galement de dcouper une grosse application, gnralement floue, en une multitude dobjets interagissant entre eux. Cela permet de dcouper un gros problme en plus petits afin de le rsoudre plus facilement. Utiliser une approche oriente objet amliore galement la maintenabilit. Plus le temps passe et plus une application est difficile maintenir. Il devient difficile de corriger des choses sans tout casser ou dajouter des fonctionnalits sans provoquer une rgression par ailleurs. Lorient objet nous aide ici limiter la casse en proposant une approche o les modifications internes un objet naffectent pas tout le reste du code, grce notamment lencapsulation. Un autre avantage de la POO est la rutilisabilit. Des objets peuvent tre rutiliss ou mme tendus grce lhritage. Cest le cas par exemple de la bibliothque de classes du framework .NET que nous avons dj utilise. Cette bibliothque nous fournit par exemple tous les objets permettant de construire des applications graphiques. Pas besoin de rinventer toute la mcanique pour grer des fentres dans une application, le framework .NET sait dj faire tout a. Nous avons juste besoin dutiliser un objet fentre , dans lequel nous pourrons mettre un objet bouton et un objet zone de texte . Ces objets hritent tous des mmes comportements, comme le fait dtre cliquable ou slectionnable, etc. De mme, des composants tout faits et prts lemploi peuvent tre vendus par des entreprises tierces (systme de log, contrles utilisateurs amliors, etc ). Il faut savoir que la POO, cest beaucoup plus que a et nous en verrons des subtilits plus loin, mais comprendre ce quest un objet est globalement suffisant pour une grande partie du tutoriel.

En rsum
Lapproche oriente objet permet de modliser son application sous la forme dinteractions entre objets. Les objets ont des proprits et peuvent faire des actions. Ils masquent la complexit d'une implmentation grce l'encapsulation. Les objets peuvent hriter de fonctionnalits d'autres objets s'il y a une relation d'hritage entre eux.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

133/381

Crer son premier objet


Ah, enfin un peu de concret et surtout de code. Dans ce chapitre, nous allons appliquer les notions que nous avons vues sur la programmation oriente objet pour continuer notre apprentissage du C#. Mme si vous n'avez pas encore apprhend exactement o la POO pouvait nous mener, ce n'est pas grave. Les notions s'affineront au fur et mesure de la lecture du tutoriel. Il est temps pour nous de commencer crer des objets, les faire hriter entre eux, etc. Bref, jouer, grce ces concepts, avec le C#. V ous verrez qu'avec un peu de pratique tout s'claircira ; vous saisirez l'intrt de la POO et comment tre efficace avec le C#.

Tous les types C# sont des objets


a y est, il a fini avec son baratin qui donne mal la tte ? Pourquoi tout ce blabla sur les objets ?

Parce que tout dans le C# est un objet. Comme dj dit, une fentre Windows est un objet. Une chane de caractres est un objet. La liste que nous avons vue plus haut est un objet. Nous avons vu que les objets possdaient des caractristiques, il sagit de proprits. Un objet peut galement faire des actions, ce sont des mthodes. Suivant ce principe, une chane de caractres est un objet et possde des proprits (par exemple sa longueur). De la mme faon, il sera possible que les chanes de caractres fassent des actions (par exemple se mettre en majuscules). Nous allons voir plus bas quil est videmment possible de crer nos propres objets (chat, chien, etc.) et que grce eux, nous allons enrichir les types qui sont notre disposition. Un peu comme nous avons dj fait avec les numrations. V oyons ds prsent comment faire, grce aux classes.

Les classes
Dans le chapitre prcdent, nous avons parl des objets mais nous avons galement parl de la dfinition de lobjet, de sa structure. Eh bien, cest exactement a, une classe. Une classe est une manire de reprsenter un objet. Le C# nous permet de crer des classes.

Nous avons dj pu voir une classe dans le code que nous avons utilis prcdemment et qui a t gnr par Visual C# Express, la classe Program. Nous ny avons pas fait trop attention, mais voil peu prs quoi elle ressemblait : Code : C# class Program { static void Main(string[] args) { } }

Cest elle qui contenait la mthode spciale Main() qui sert de point dentre lapplication. Nous pouvons dcouvrir avec des yeux neufs le mot cl class qui comme son nom le suggre permet de dfinir une classe, c'est--dire la structure dun objet. Rappelez-vous, les objets peuvent avoir des caractristiques et faire des actions. Ici, cest exactement ce quil se passe. Nous avons dfini la structure dun objet Program qui contient une action : la mthode Main(). V ous aurez remarqu au passage que pour dfinir une classe, nous utilisons nouveau les accolades permettant de crer un bloc de code qui dlimite la classe. Passons sur cette classe particulire et lanons-nous dans la cration dune classe qui nous servira crer des objets. Par exemple, une classe Voiture. noter quil est possible de crer une classe plusieurs endroits dans le code, mais en gnral, nous utiliserons un nouveau

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

134/381

fichier, du mme nom que la classe, qui lui sera entirement ddi. Une rgle dcriture commune beaucoup de langage de programmation est que chaque fichier doit avoir une seule classe. Faisons un clic droit sur notre projet pour ajouter une nouvelle classe :

Visual C# express nous ouvre sa fentre permettant de faire lajout dun lment en se positionnant sur llment Classe. Nous pourrons donner un nom cette classe : Voiture.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


V ous remarquerez que les classes commencent en gnral par une majuscule. Visual C# Express nous gnre le code suivant : Code : C# using using using using System; System.Collections.Generic; System.Linq; System.Text;

135/381

namespace MaPremiereApplication { class Voiture { } }

Nous retrouvons le mot-cl class suivi du nom de notre classe Voiture et les accolades ouvrantes et fermantes permettant de dlimiter notre classe. Notons galement que cette classe fait partie de lespace de nom MaPremireApplication qui est lespace de nom par dfaut de notre projet. Pour nous simplifier le travail, Visual C# Express nous a galement inclus quelques espaces de noms souvent utiliss. Mais pour linstant cette classe ne fait pas grand-chose. Comme cette classe est vide, elle ne possde ni proprits, ni actions. Nous ne pouvons absolument rien faire avec part en crer une instance, c'est--dire un objet. Cela se fait grce lutilisation du mot-cl new. Nous y reviendrons plus en dtail plus tard, mais cela donne : Code : C# static void Main(string[] args) { Voiture voitureNicolas = new Voiture(); Voiture voitureJeremie = new Voiture(); }

Nous avons cr deux instances de lobjet Voiture et nous les stockons dans les variable voitureNicolas et voitureJeremie. Si vous vous rappelez bien, nous aurions logiquement d crire : Code : C# MaPremiereApplication.Voiture voitureNicolas = new MaPremiereApplication.Voiture();

Ou alors positionner le using qui allait bien, permettant dinclure lespace de nom MaPremiereApplication. En fait, ici cest superflu vu que nous crons les objets depuis la mthode Main() qui fait partie de la classe Program faisant partie du mme espace de nom que notre classe.

Les mthodes
Nous venons de crer notre objet Voiture mais nous ne pouvons pas en faire grand-chose. Ce qui est bien dommage. a serait bien que notre voiture puisse klaxonner par exemple si nous sommes bloqus dans des embouteillages. Bref, que notre voiture soit capable de faire des actions. Qui dit action dit mthode . Nous allons pouvoir dfinir des mthodes faisant partie de notre objet Voiture. Pour ce faire, il suffit de crer une mthode,

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


comme nous lavons dj vu, directement dans le corps de la classe : Code : C# class Voiture { void Klaxonner() { Console.WriteLine("Pouet !"); } }

136/381

Notez quand mme labsence du mot-cl static que nous tions obligs de mettre avant. Je vous expliquerai un peu plus loin pourquoi. Ce qui fait que si nous voulons faire klaxonner notre voiture, nous aurons juste besoin dinvoquer la mthode Klaxonner() depuis lobjet Voiture, ce qui scrit : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Klaxonner();

Cela ressemble beaucoup ce que nous avons dj fait. En fait, nous avons dj utilis des mthodes sur des objets. Rappelezvous, nous avons utilis la mthode Add() permettant dajouter une valeur une liste : Code : C# List<int> maListe = new List<int>(); maListe.Add(1);

Comme nous avons un peu plus de notions dsormais, nous pouvons remarquer que nous instancions un objet List (plus prcisment, une liste dentier) grce au mot cl new et que nous invoquons la mthode Add de notre liste pour lui ajouter lentier 1. Nous avons fait pareil pour obtenir un nombre alatoire, dans une criture un peu plus concise. Nous avions crit : Code : C# int valeurATrouver = new Random().Next(0, 100);

Ce qui peut en fait scrire : Code : C# Random random = new Random(); int valeurATrouver = random.Next(0, 100);

Nous crons un objet du type Random grce new puis nous appelons la mthode Next() qui prend en paramtres les bornes du nombre alatoire que nous souhaitons obtenir (0 tant inclus et 100 exclu). Puis nous stockons le rsultat dans un entier.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Et oui, nous avons manipul quelques objets sans le savoir Revenons notre embouteillage et compilons le code nous permettant de faire klaxonner notre voiture : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Klaxonner();

137/381

Impossible de compiler, le compilateur nous indique lerreur suivante : Code : Console

MaPremiereApplication.Voiture.Klaxonner()' est inaccessible en raison de son niveau de pr

Diantre ! Dj un premier chec dans notre apprentissage de lobjet ! V ous aurez devin grce au message derreur que la mthode Klaxonner() semble inaccessible. Nous expliquerons un peu plus bas de quoi il sagit. Pour linstant, nous allons juste prfixer notre mthode du mot-cl public, comme ceci : Code : C# class Voiture { public void Klaxonner() { Console.WriteLine("Pouet !"); } }

Nous allons y revenir juste en-dessous, mais le mot-cl public permet dindiquer que la mthode est accessible depuis nimporte o. Excutons notre application et nous obtenons :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

138/381

Wahou, notre premire action dun objet. Bien sr, ces mthodes peuvent galement avoir des paramtres et renvoyer un rsultat. Par exemple : Code : C# class Voiture { public bool VitesseAutorisee(int vitesse) { if (vitesse > 90) return false; else return true; } }

Cette mthode accepte une vitesse en paramtre et si elle est suprieure 90, alors la vitesse nest pas autorise. Cette mthode pourrait galement scrire : Code : C# class Voiture { public bool VitesseAutorisee(int vitesse) { return vitesse <= 90; } }

En effet, nous souhaitons renvoyer faux si la vitesse est suprieure 90 et vrai si la vitesse est infrieure ou gale. Donc en fait, nous souhaitons renvoyer la valeur du rsultat de la comparaison dinfriorit ou dgalit de la vitesse 90, c'est- -dire :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# class Voiture { public bool VitesseAutorisee(int vitesse) { bool estVitesseAutorisee = vitesse <= 90; return estVitesseAutorisee; } }

139/381

Ce que nous pouvons crire finalement en une seule ligne comme prcdemment. Il est bien sr possible davoir plusieurs mthodes dans une mme classe et elles peuvent sappeler entre elles, par exemple : Code : C# class Voiture { public bool VitesseAutorisee(int vitesse) { return vitesse <= 90; } public void Klaxonner() { if (!VitesseAutorisee(180)) Console.WriteLine("Pouet !"); }

Quitte rouler une vitesse non autorise, autant faire du bruit !

Notion de visibilit
Ok, le mot-cl public nous a bien sauv la vie, mais quest-ce donc ?

En fait, je lai rapidement voqu et nous nous sommes bien rendu compte que sans ce mot-cl, c'est impossible de compiler car la mthode nest pas accessible. Le mot-cl public sert indiquer que notre mthode peut tre accessible depuis dautres classes ; en loccurrence dans notre exemple depuis la classe Program. Cest--dire que sans ce mot-cl, il est impossible dautres objets dutiliser cette mthode. Pour faire en sorte quune mthode soit inaccessible, nous pouvons utiliser le mot-cl private. Ce mot-cl permet davoir une mthode qui nest accessible que depuis la classe dans laquelle elle est dfinie. Prenons lexemple suivant : Code : C# class Voiture { public bool Demarrer() { if (ClesSurLeContact()) { DemarrerLeMoteur(); return true; } return false; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public void SortirDeLaVoiture() { if (ClesSurLeContact()) PrevenirLUtilisateur(); } private bool ClesSurLeContact() { // faire quelque chose pour vrifier return true; } private void DemarrerLeMoteur() { // faire quelque chose pour dmarrer le moteur } private void PrevenirLUtilisateur() { Console.WriteLine("Bip bip bip"); }

140/381

Ici seules les mthodes Demarrer() et SortirDeLaVoiture() sont utilisables depuis une autre classe, c'est--dire que ce sont les seules mthodes que nous pourrons invoquer, car elles sont publiques. Les autres mthodes sont prives la classe et ne pourront tre utilises qu lintrieur de la classe elle-mme. Les autres classes nont pas besoin de savoir comment dmarrer le moteur ou comment vrifier que les cls sont sur le contact, elles nont besoin que de pouvoir dmarrer ou sortir de la voiture. Les mthodes prives sont exclusivement rserves lusage interne de la classe. Notez dailleurs que la compltion automatique nest pas propose pour les mthodes inaccessibles.

Il existe dautres indicateurs de visibilit que nous allons rapidement dcrire : Visibilit public protected private internal Accs non restreint Accs depuis la mme classe ou depuis une classe drive Accs uniquement depuis la mme classe Accs restreint la mme assembly Description

protected internal Accs restreint la mme assembly ou depuis une classe drive

Les visibilits qui vont le plus vous servir sont reprsentes par les mots-cls public et private. Nous verrons que le motcl protected va servir un peu plus tard quand nous parlerons dhritage. Notez quinternal pourra tre utilis une fois que nous aurons bien maitris toutes les notions. Ces mots-cls sont utilisables avec beaucoup dautres concepts. Nous avons utilis les mthodes pour les illustrer mais ceci est galement valable pour les classes ou les proprits que nous allons dcouvrir juste aprs. Oui mais, au dbut, nous avons pu dclarer une classe sans prciser de visibilit et pareil pour la premire mthode qui ne compilait pas cest normal ?

Oui, il existe des visibilits par dfaut suivant les types dclars. V ous aurez compris par exemple que la visibilit par dfaut dune mthode est prive si lon ne spcifie pas le mot cl. Pour viter tout risque et toute ambigit, il est recommand de toujours indiquer la visibilit. Ce que nous ferons dsormais

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


dans ce tutoriel, maintenant que nous savons de quoi il sagit.

141/381

Les proprits
Des objets cest bien. Des actions sur ces objets, cest encore mieux. Il nous manque encore les caractristiques des objets. Cest l quinterviennent les proprits. Sans le savoir, vous avez dj utilis des proprits, par exemple dans le code suivant : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; for (int i = 0; i < jours.Length; i++) { Console.WriteLine(jours[i]); }

Dans la boucle, nous utilisons jours.Length. Nous utilisons en fait la proprit Length du tableau jours , un tableau tant bien sr un objet. Nous avons pu utiliser dautres proprits, par exemple dans linstruction suivante : Code : C# List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" }; for (int i = 0; i < jours.Count; i++) { Console.WriteLine(jours[i]); }

Ici, Count est la proprit de la liste jours . De la mme faon, nous avons la possibilit de crer des proprits sur nos classes pour permettre dajouter des caractristiques nos objets. Par exemple, nous pouvons rajouter les proprits suivantes notre voiture : une couleur, une marque, une vitesse. Il y a plusieurs faons de rajouter des caractristiques un objet. La premire est dutiliser des variables membres.

Les variables membres :


Ici en fait, un objet peut avoir une caractristique sous la forme dune variable publique qui fait partie de la classe. Pour ce faire, il suffit de dfinir simplement la variable lintrieur des blocs de code dlimitant la classe et de lui donner la visibilit public. Rajoutons par exemple une chaine de caractres permettant de stocker la couleur de la voiture : Code : C# public class Voiture { public string Couleur; }

Notez que jai rajout les visibilits pour la classe et pour la variable. Grce ce code, la chaine de caractres Couleur est dsormais une caractristique de la classe V oiture. Nous pourrons lutiliser en faisant suivre notre objet de loprateur . suivi du nom de la variable. Ce qui donne :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# Voiture voitureNicolas voitureNicolas.Couleur Voiture voitureJeremie voitureJeremie.Couleur = = = = new Voiture(); "rouge"; new Voiture(); "verte";

142/381

Cela ressemble beaucoup ce que nous avons dj fait. Nous utilisons le . pour accder aux proprits dun objet. Comme dhabitude, les variables vont pouvoir stocker des valeurs. Ainsi, nous pourrons avoir une voiture rouge pour Nicolas et une voiture verte pour Jrmie. Notez ici quil sagit bien de variables membres et non de vraies proprits. En gnral, les variables dune classe ne doivent jamais tre publiques. Nous utiliserons rarement cette construction.

Les proprits :
Les proprits sont en fait des variables volues. Elles sont mi-chemin entre une variable et une mthode. Prenons cet exemple : Code : C# public class Voiture { private int vitessePrivee; public int Vitesse { get { return vitessePrivee; } set { vitessePrivee = value; } } }

Nous pouvons voir que nous dfinissons dans un premier temps une variable prive, vitessePrivee de type entier. Comme prvu, cette variable est masque pour les utilisateurs dobjets Voiture. Ainsi, le code suivant : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.vitessePrivee = 50;

provoquera lerreur de compilation dsormais bien connue : Code : Console MaPremiereApplication.Voiture.vitessePrivee' est inaccessible en raison de son niveau de

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

143/381

Par contre, nous en avons profit pour dfinir la proprit Vitesse, de type int. Pour ceci, nous avons dfini une partie de la proprit avec le mot cl get suivi dun return vitessePrivee. Et juste en dessous, nous avons utilis le mot cl set, suivi de vitessePrivee = value. Ce que nous avons fait, cest dfinir la possibilit de lire la proprit grce au mot cl get. Ici, la lecture de la proprit nous renvoie la valeur de la variable prive. De la mme faon, nous avons dfini la possibilit daffecter une valeur la proprit en utilisant le mot cl set et en affectant la valeur la variable prive. Les blocs de code dlimits par get et set se comportent un peu comme des mthodes, elles ont un corps qui est dlimit par des accolades et dans le cas du get, elle doit renvoyer une valeur du mme type que la proprit. noter que dans le cas du set, value est un mot cl qui permet de dire : la valeur que nous avons affecte la proprit . Prenons lexemple suivant : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Vitesse = 50; Console.WriteLine(voitureNicolas.Vitesse);

La premire instruction instancie bien sr une voiture. La deuxime instruction consiste appeler le bloc de code set de Vitesse qui met la valeur 50 dans la pseudo-variable value qui est stocke ensuite dans la variable prive. Lorsque nous appelons la troisime instruction, nous lisons la valeur de la proprit et pour ce faire, nous passons par le get qui nous renvoie la valeur de la variable prive. Ok, cest super, mais dans ce cas, pourquoi passer par une proprit et pas par une variable ? Mme s'il parait que les variables ne doivent jamais tre publiques

Eh bien parce que dans ce cas-l, la proprit peut faire un peu plus que simplement renvoyer une valeur. Et aussi parce que nous masquons la structure interne de notre classe ceux qui veulent lutiliser. Nous pourrions trs bien envisager daller lire la vitesse dans les structures internes du moteur, ou en faisant un calcul pouss par rapport au coefficient du vent et de lge du capitaine (ou plus vraisemblablement en allant lire la valeur en base de donnes). Et ici, nous pouvons tirer parti de la puissance des proprits pour masquer tout a lappelant qui lui na besoin que dune vitesse. Par exemple : Code : C# private int vitessePrivee; public int Vitesse { get { int v = vitesseDesRoues * rayon * coefficient; // ce calcul est compltement farfelu ! MettreAJourLeCompteur(); AdapterLaVitesseDesEssuieGlaces(); return v; } set { // faire la mise jour des variables internes MettreAJourLeCompteur(); AdapterLaVitesseDesEssuieGlaces();

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} AdapterLaVitesseDesEssuieGlaces();

144/381

En faisant tout a dans le bloc de code get, nous masquons les rouages de notre classe lutilisateur. Lui, il na besoin que dobtenir la vitesse, sans sencombrer du compteur ou des essuie-glaces. Bien sr, la mme logique peut sadapter au bloc de code qui permet daffecter une valeur la proprit, set. Il est galement possible de rendre une proprit en lecture seule, cest--dire non modifiable par les autres objets. Il pourra par exemple sembler bizarre de positionner une valeur la vitesse alors quen fait, pour mettre jour la vitesse, il faut appeler la mthode AppuyerPedale(double forceAppui). Pour empcher les autres objets de pouvoir directement mettre jour la proprit Vitesse, il suffit de ne pas dclarer le bloc de code set et de ne garder quun get. Par exemple : Code : C# public class Voiture { private int vitessePrivee; public int Vitesse { get { // faire des calculs ... return vitessePrivee; } } }

Ce qui fait que si nous tentons daffecter une valeur la proprit Vitesse depuis une autre classe, par exemple : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Vitesse = 50;

Nous aurons lerreur de compilation suivante : Code : Console

La proprit ou l'indexeur 'MaPremiereApplication.Voiture.Vitesse' ne peut pas tre assig - il est en lecture seule

Le compilateur nous indique donc trs justement quil est impossible de faire cette affectation car la proprit est en lecture seule. Il devient donc impossible pour un utilisateur de cette classe de modifier la vitesse de cette faon. De mme, il est possible de dfinir une proprit pour quelle soit accessible en criture seule. Il suffit de dfinir uniquement le bloc de code set : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


private double acceleration; public double Acceleration { set { acceleration = value; } }

145/381

Ainsi, si nous tentons dutiliser la proprit en lecture, avec par exemple : Code : C# Console.WriteLine(voitureNicolas.Acceleration);

Nous aurons lerreur de compilation attendue : Code : Console La proprit ou l'indexeur 'MaPremiereApplication.Voiture.Acceleration' ne peut pas tre

Ce bridage daccs des proprits prend tout son sens quand nous souhaitons exposer nos objets dautres consommateurs qui nont aucun intrt connaitre la structure interne de notre classe. Cest un des principes de lencapsulation.

Les proprits auto-implmentes :


Les proprits auto-implmentes sont une fonctionnalit que nous allons beaucoup utiliser. Il sagit de la dfinition dune proprit de manire trs simplifie qui va nous servir dans la grande majorit des cas o nous aurons besoin dcrire des proprits. Dans ce tutoriel, nous lutiliserons trs souvent. Ainsi, le code suivant que nous avons dj vu : Code : C# private int vitesse; public int Vitesse { get { return vitesse; } set { vitesse = value; } }

est un cas trs frquent dutilisation de proprits. Nous exposons ici une variable prive travers les proprits get et set. Lcriture du dessus est quivalente la suivante : Code : C# public int Vitesse { get; set; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

146/381

Dans ce cas, le compilateur fait le boulot lui-mme, il gnre (dans le code compil) une variable membre qui va servir stocker la valeur de la proprit. Cest exactement pareil, sauf que cela nous simplifie grandement lcriture. En plus, nous pouvons encore acclrer son criture en utilisant ce quon appelle des snippets qui sont des extraits de code. Pour les utiliser, il suffit de commencer crire un mot et Visual C# nous complte le reste. Un peu comme la compltion automatique sauf que cela fonctionne pour des bouts de code trs rptitifs et trs classiques crire. Commencez par exemple taper prop , Visual C# nous propose plusieurs extraits de code :

Appuyez sur tab ou entre pour slectionner cet extrait de code et appuyez ensuite sur tab pour que Visual C# gnre lextrait de code correspondant la proprit auto-implmente. V ous aurez :

Ici, int est surlign et vous pouvez, si vous le souhaitez, changer le type de la proprit, par exemple string. Appuyez nouveau sur tab et Visual C# surligne le nom de la proprit, que vous pouvez nouveau changer. Appuyez enfin sur entre pour terminer la saisie et vous aurez une belle proprit auto-implmente :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

147/381

V ous avez pu remarquer quen commenant taper prop , Visual C# express vous a propos dautres extraits de code, par exemple propfull qui va gnrer la proprit complte telle quon la vue un peu plus haut. Dautres extraits de code existent, comme propg qui permet de dfinir une proprit en lecture seule. En effet, comme au chapitre prcdent, il est possible de dfinir des proprits auto-implmentes en lecture seule ou en criture seule avec une criture simplifie. Dans le cas des proprits auto-implmentes, il y a cependant une subtilit. Pour avoir de la lecture seule, nous devons indiquer que l'affectation est prive, comme on peut le voir en utilisant lextrait de code propg . Visual C# express nous gnre le bout de code suivant : Code : C# public int Vitesse { get; private set; }

En positionnant une proprit dcriture en prive, Visual C# express autorise la classe V oiture modifier la valeur de Vitesse, que ce soit par une mthode ou par une proprit. A noter que si nous n'avions pas mis private set et que nous avions simplement supprim le set, alors la compilation aurait t impossible. En effet, il savre difficile dexploiter une proprit auto-implmente en lecture alors que nous navons pas la possibilit de lui donner une valeur. Ou inversement.

Alors, pourquoi nous avoir parl de la possibilit de compltement supprimer la lecture ou lcriture ? Ce nest pas plus intressant de toujours mettre la proprit en private ?

Si cest une proprit auto-implmente, videmment que si. Par contre, si nous nutilisons pas une proprit auto-implmente et que nous utilisons une variable membre pour sauvegarder la valeur de la proprit, nous pourrons ventuellement modifier ou lire la valeur de la variable partir dune mthode ou dune autre proprit. Bref, maintenant que vous connaissez les deux syntaxes, vous pourrez utiliser la plus adapte votre besoin. V pour les proprits. oil noter que quand nous avons beaucoup de proprits initialiser sur un objet, nous pouvons utiliser une syntaxe plus concise. Par exemple, les instructions suivantes : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Couleur = "Bleue"; voitureNicolas.Marque = "Peugeot"; voitureNicolas.Vitesse = 50;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


sont quivalentes linstruction : Code : C# Voiture voitureNicolas = new Voiture { Couleur = "Bleue", Marque = "Peugeot", Vitesse = 50 };

148/381

Les accolades servent ici initialiser les proprits au mme moment que linstanciation de lobjet. Note : cela parait vident, mais il est bien sr possible daccder aux proprits dune classe depuis une mthode de la mme classe.

En rsum
On utilise des classes pour reprsenter quasiment la plupart des objets. On utilise le mot-cl class pour dfinir une classe et le mot-cl new pour l'instancier. Une classe peut possder des caractristiques (les proprits) et peut faire des actions (les mthodes).

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

149/381

Manipuler des objets


Maintenant que nous avons bien vu comment dfinir des objets, il est temps de savoir les utiliser. Nous allons voir dans ce chapitre quelles sont les subtilits de l'instanciation des objets. V ous verrez notamment ce qu'est un constructeur et qu'on peut avoir des valeurs nulles pour des objets. N'hsitez pas jouer avec tous ces concepts, il est important d'tre l'aise avec les bases pour pouvoir tre efficace avec les concepts avancs.

Le constructeur
Le constructeur est une mthode particulire de lobjet qui permet de faire des choses au moment de la cration dun objet, cest-dire au moment o nous utilisons le mot-cl new. Il est en gnral utilis pour initialiser des valeurs par dfaut dun objet. Par exemple, si nous voulons que lors de la cration dune voiture, elle ait automatiquement une vitesse, nous pouvons faire : Code : C# public class Voiture { public int Vitesse { get; set; } public Voiture() { Vitesse = 5; }

Le constructeur est en fait une mthode spciale qui a le mme nom que la classe et qui ne possde pas de type de retour. Elle est appele lors de la cration de lobjet, avec new. Pour illustrer le comportement du constructeur, ajoutons une mthode Rouler notre classe, de cette faon : Code : C# public class Voiture { public int Vitesse { get; set; } public Voiture() { Vitesse = 5; } public void Rouler() { Console.WriteLine("Je roule " + Vitesse + " km/h"); }

Que nous pourrons appeler ainsi : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Rouler(); voitureNicolas.Vitesse = 50; voitureNicolas.Rouler();

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Au moment de linstanciation de lobjet avec new, la vitesse va tre gale 5. Nous faisons rouler la voiture. Puis nous changeons la vitesse pour la passer 50 et nous faisons nouveau rouler la voiture. Nous aurons :

150/381

Le constructeur est la premire mthode tre appele lors de la cration dun objet. Cest lendroit appropri pour faire des initialisations, ou pour charger des valeurs, etc. Le constructeur que nous avons vu est ce quon appelle le constructeur par dfaut, car il ne possde pas de paramtres. Il est possible de passer des paramtres un constructeur, pour initialiser des variables de notre classe avec des valeurs. Pour ce faire, nous devons dclarer un constructeur avec un paramtre ; par exemple : Code : C# public class Voiture { public int Vitesse { get; set; } public Voiture() { Vitesse = 5; } public Voiture(int vitesse) { Vitesse = vitesse; } public void Rouler() { Console.WriteLine("Je roule " + Vitesse + " km/h"); }

Ainsi, nous pourrons crer un objet voiture en lui prcisant une vitesse par dfaut de cette faon : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Voiture voitureNicolas = new Voiture(20);

151/381

Aprs ceci, la variable voitureNicolas aura une vitesse de 20. Bien sr, nous pourrions faire la mme chose sans utiliser de constructeur, en affectant une valeur la proprit aprs avoir instanci lobjet. Ce qui fonctionnerait tout fait. Sauf quil ne se passe pas exactement la mme chose. Le constructeur est vraiment appel en premier, ds quon utilise new pour crer un objet. Les proprits sont affectes fatalement aprs, donc tout dpend de ce que lon veut faire. Donc, oui, on pourrait affecter une valeur des proprits pour faire ce genre dinitialisation juste aprs avoir instanci notre objet mais cela nous oblige crire une instruction supplmentaire qui pourrait ne pas paraitre vidente ou obligatoire. Une chose est sre avec le constructeur, cest que nous sommes obligs dy passer et ceci, peu importe la faon dont on utilise la classe. Linitialisation devient donc obligatoire, on vite le risque quune proprit soit nulle. noter quil est possible de cumuler les constructeurs tant quils ont chacun des paramtres diffrents. Dans notre exemple, nous pourrons donc crer des voitures de deux faons diffrentes : Code : C# Voiture voitureNicolas = new Voiture(); // vitesse vaut 5 Voiture voitureJeremie = new Voiture(20); // vitesse vaut 20

Il est aussi possible de ne pas dfinir de constructeur par dfaut et davoir uniquement un constructeur possdant des paramtres. Dans ce cas, il devient impossible dinstancier un objet sans lui passer de paramtres.

Instancier un objet
Nous allons revenir prsent sur linstanciation dun objet. Comme nous venons de le voir, nous utilisons le mot cl new pour crer une instance dun objet. Cest lui qui permet la cration dun objet. Il appelle le constructeur correspondant. Si aucun constructeur nexiste, il ne se passera rien de plus quune cration de base. Par exemple : Code : C# Voiture voitureNicolas = new Voiture();

Pour rentrer un peu dans la technique, au moment de linstanciation dun objet, loprateur new cre lobjet et le met une place disponible en mmoire. Cette adresse mmoire est conserve dans la variable voitureNicolas. On dit que voitureNicolas contient une rfrence vers lobjet. Nous verrons un peu plus tard ce que cela implique. Ce principe ressemble un peu au pointeur que nous pourrions trouver dans des langages comme le C ou le C++. Mais typiquement, si vous savez ce quest un pointeur, vous pouvez vous reprsenter une rfrence comme un pointeur volu.

Comme pour les types que nous avons vus plus haut, nous sommes obligs dinitialiser un objet avant de lutiliser. Sinon, Visual C# Express nous gnrera une erreur de compilation. Par exemple, les instructions suivantes : Code : C# Voiture voitureNicolas; voitureNicolas.Vitesse = 5;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


provoqueront lerreur de compilation suivante : Code : Console Utilisation d'une variable locale non assigne 'voitureNicolas'

152/381

En effet, Visual C# Express est assez intelligent pour se rendre compte que lon va essayer daccder un objet qui na pas t initialis. Il faut toujours initialiser une variable avant de pouvoir lutiliser. Comme pour les types prcdents, il est possible de dissocier la dclaration dun objet de son instanciation, en crivant les instructions sur plusieurs lignes, par exemple : Code : C# Voiture voitureNicolas; // des choses voitureNicolas = new Voiture();

ceci est possible tant que nous nutilisons pas la variable voitureNicolas avant de lavoir instancie. Les objets peuvent galement avoir une valeur nulle. Ceci est diffrent de labsence dinitialisation car la variable est bien initialise et sa valeur vaut nul . Ceci est possible grce lemploi du mot-cl null. Code : C# Voiture voitureNicolas = null;

Attention, il est par contre impossible daccder un objet qui vaut null. Eh oui, comment voulez-vous vous asseoir sur une chaise qui nexiste pas ? Eh bien vous vous retrouverez avec les fesses par terre, personne ne vous a indiqu que la chaise nexistait pas. Cest pareil pour notre application, si nous tentons dutiliser une voiture qui nexiste pas, nous aurons droit un beau plantage. Par exemple, avec le code suivant : Code : C# Voiture voitureNicolas = null; voitureNicolas.Vitesse = 5;

vous naurez pas derreur la compilation, par contre vous aurez :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

153/381

Comme nous lavons dj vu, le programme nous affiche une exception ; nous avons dit que ctait simplement une erreur qui faisait planter notre programme. Pas bien ! Surtout que cela se passe au moment de lexcution. Nous perdons toute crdibilit ! Ici, le programme nous dit que la rfrence dun objet nest pas dfinie une instance dun objet. Concrtement, cela veut dire que nous essayons de travailler sur un objet null. Pour viter ce genre derreur lexcution, il faut imprativement instancier ses objets, en utilisant loprateur new, comme nous lavons dj vu. Il nest cependant pas toujours pertinent dinstancier un objet dont on pourrait ne pas avoir besoin. Le C# nous offre donc la possibilit de tester la nullit dun objet. Il suffit dutiliser loprateur de comparaison == en comparant un objet au mot-cl null, par exemple : Code : C# string prenom = "Nicolas"; Voiture voiture = null; if (prenom == "Nicolas") voiture = new Voiture { Vitesse = 50 }; if (voiture == null) { Console.WriteLine("Vous n'avez pas de voiture"); } else { voiture.Rouler(); }

Ainsi, seul Nicolas possdera une voiture et le test de nullit sur lobjet permet dviter une erreur dexcution si le prnom est diffrent. Maintenant que vous connaissez le mot-cl null et que vous savez quun objet peut prendre une valeur nulle, nous allons revenir sur un point que jai rapidement abord auparavant. Je ne sais pas si vous vous en rappelez, mais lors de ltude des oprateurs logiques jai parl du fait que loprateur OU ( || ) valuait la premire condition et si elle tait vraie alors il nvaluait pas la suivante, considrant que de toutes faons, le rsultat allait tre vrai. Ce dtail prend toute son importance dans le cas suivant :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# if (voiture == null || voiture.Couleur == "Bleue") { // faire quelque chose }

154/381

Dans ce cas, si la voiture est effectivement nulle, alors le fait dvaluer la proprit Couleur de la voiture devrait renvoyer une erreur. Heureusement, le C# avait prvu le coup, si la premire condition est vraie alors la seconde ne sera pas value, ce qui vitera lerreur. Ainsi, nous sommes srs de navoir aucune voiture bleue. Il est par contre vident quune telle condition utilisant loprateur ET (&&) est une hrsie car pour que la condition soit vraie, le C# a besoin dvaluer les deux oprandes. Et donc si la voiture est nulle, lutilisation dune proprit sur une valeur nulle renverra une erreur. Notons galement que lorsque nous utilisons loprateur ET (&&) si la premire oprande est fausse, alors de la mme faon, il nvalue pas la seconde, car pour que la condition soit vraie il faut que les deux le soient. Ce qui fait quil est galement possible dcrire ce code : Code : C# if (voiture != null && voiture.Couleur == "Rouge") { // faire autre chose }

qui ne provoquera pas derreur lexcution, mme si voiture vaut null car dans ce cas, le fait que le premier test soit faux vitera le test de lautre partie de lexpression. V ous verrez que vous aurez loccasion dutiliser le mot-cl null rgulirement.

Le mot-cl this

Lorsque nous crivons le code dune classe, le mot-cl this reprsente lobjet dans lequel nous nous trouvons. Il permet de clarifier ventuellement le code, mais Il est gnralement facultatif. Ainsi, pour accder une variable de la classe ou ventuellement une mthode, nous pouvons les prfixer par this. . Par exemple, nous pourrions crire notre classe de cette faon : Code : C# public class Voiture { public int Vitesse { get; set; } public string Couleur { get; set; } public Voiture() { this.Vitesse = 5; } public void Rouler() { Console.WriteLine("Je roule " + this.Vitesse + " km/h"); } public void Accelerer(int acceleration) { this.Vitesse += acceleration; this.Rouler(); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

155/381

Ici, dans le constructeur, nous utilisons le mot-cl this pour accder la proprit Vitesse. Cest la mme chose dans la mthode Rouler. De la mme faon, on peut utiliser this.Rouler() pour appeler la mthode Rouler depuis la mthode Accelerer(). Cest une faon pour la classe de dire : Regardez, avec this, cest "ma variable moi" . Notez bien sr que sans le mot-cl this, notre classe compilera quand mme et sera tout fait fonctionnelle. Ce mot-cl est facultatif mais il peut aider bien faire la diffrence entre ce qui appartient la classe et ce qui fait partie des paramtres des mthodes ou dautres objets utiliss. Suivant les personnes, le mot-cl this est soit systmatiquement utilis, soit jamais. Je fais plutt partie des personnes qui ne lutilisent jamais. Il arrive par contre certaines situations o il est absolument indispensable, comme celle-ci, mais en gnral, jessaie dviter ce genre de construction : Code : C# public void ChangerVitesse(int Vitesse) { this.Vitesse = Vitesse; }

V ous remarquerez que le paramtre de la mthode ChangerVitesse() et la proprit ou variable membre de la classe ont exactement le mme nom. Ceci est possible ici mais source derreurs, les variables ayant des portes diffrentes. Il savre que dans ce cas, le mot-cl this est indispensable. On pourra donc viter lambigit en prfixant la proprit membre avec le mot-cl this. Je recommande plutt de changer le nom du paramtre, quitte utiliser une minuscule, ce qui augmentera la lisibilit et vitera des erreurs potentielles. En gnral, des conventions de nommage pourront nous viter de nous retrouver dans ce genre de situation. a y est, nous savons instancier et utiliser des objets. Savoir crer et utiliser ses propres objets est trs important dans un programme orient objet. V ous allez galement avoir besoin trs rgulirement dutiliser des objets tout fait, comme ceux venant de la bibliothque de classe du framework .NET. Nous comprenons dailleurs mieux pourquoi elle sappelle bibliothque de classes . Il sagit bien dun ensemble de classes utilisables dans notre application et nous pourrons instancier les objets relatifs ces classes pour nos besoins. Comme ce que nous avions dj fait auparavant sans trop le savoir, avec lobjet Random par exemple Nhsitez pas relire ce chapitre ainsi que le prcdent si vous navez pas parfaitement compris toutes les subtilits de la cration dobjet. Cest un point important du tutoriel. Cependant, nous navons pas encore tout vu sur le C# et la POO. Alors ne nous arrtons pas en si bon chemin et attaquons des concepts un peu plus avancs.

En rsum
Les classes possdent une mthode particulire, appele l'instanciation de l'objet : le constructeur. Une instance d'une classe peut tre initialise avec une valeur nulle grce au mot-cl null. Le mot-cl this reprsente l'objet en cours de la classe.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

156/381

La POO et le C#
Dans ce chapitre, vous allez vous immerger un peu plus dans les subtilits de la POO en utilisant le C#. Il est temps un peu de tourmenter nos objets et de voir ce qu'ils ont dans le ventre. Ainsi, nous allons voir comment les objets hritent les uns des autres ou comment fonctionnent les diffrents polymorphismes. Nous allons galement voir comment tous ces concepts se retrouvent dans le quotidien d'un dveloppeur C#.

Des types, des objets, type valeur et type rfrence


Ok, je sais maintenant crer des objets, mais je me rappelle quau dbut du tutoriel, nous avons manipul des int et des string et que tu as appel a des types ; et aprs, tu nous dis que tout est objet Tu serais pas en train de raconter nimporte quoi ?

Eh bien non, perspicace lecteur ! Prcisons un peu maintenant que vous avez de meilleures connaissances. Jai bien dit que tout tait objet, je le maintiens, mme sous la torture. C'est--dire que mme les types simples comme les entiers int ou les chanes de caractres sont des objets. Jen veux pour preuve ce simple exemple : Code : C# int a = 10; string chaine = a.ToString(); chaine = "abc" + chaine; string chaineEnMajuscule = chaine.ToUpper(); Console.WriteLine(chaineEnMajuscule); Console.WriteLine(chaineEnMajuscule.Length);

La variable a est un entier. Nous appelons la mthode ToString() sur cet entier. Mme si nous navons pas encore vu quoi elle servait, nous pouvons supposer quelle effectue une action qui consiste transformer lentier en chane de caractres. Nous concatnons ensuite la chane abc cette chane et nous effectuons une action qui, travers la mthode ToUpper(), met la chaine en majuscule. Enfin, la mthode Console.WriteLine nous affiche ABC10 puis nous affiche la proprit Length de la chane de caractres qui correspond bien sr sa taille. Pour crer une chane de caractres, nous utilisons le mot-cl string. Sachez que ce mot-cl est quivalent la classe String (notez la diffrence de casse). En crant une chane de caractres, nous avons instanci un objet dfini par la classe String. Mais alors, pourquoi utiliser string et non pas String ?

En fait, le mot-cl string est ce quon appelle un alias de la classe String qui se situe dans lespace de nom System. De mme, le mot-cl int est un alias de la structure Int32 qui se situe galement dans lespace de nom System (nous verrons un peu plus loin ce qu'est vraiment une structure). Ce qui fait que les instructions suivantes : Code : C# int a = 10; string chaine = "abc";

sont quivalentes celles-ci :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# System.Int32 a = 10; System.String chaine = "abc";

157/381

En pratique, comme on la dj fait, on utilise plutt les alias que les classes quils reprsentent.

Cependant, les entiers, les boolens et autres types simples sont ce quon appelle des types intgrs. Et mme si ce sont des objets part entire (mthodes, proprits, ), ils ont des particularits, notamment dans la faon dont ils sont grs par le framework .NET. On les appelle des types valeur, car les variables de ce type possdent la vraie valeur de ce quon leur affecte a contrario des classes qui sont des types rfrence dont les variables possdent simplement un lien vers un objet en mmoire. Par exemple : Code : C# int entier = 5;

Ici, la variable contient vraiment lentier 5. Alors que pour linstanciation suivante : Code : C# Voiture voitureNicolas = new Voiture();

La variable voitureNicolas contient une rfrence vers lobjet en mmoire. On peut imaginer que le type rfrence est un peu comme si on disait que ma maison se situe 9 rue des bois . Ladresse a t crite sur un bout de papier et rfrence ma maison qui ne se situe bien sr pas au mme endroit que le bout de papier. Si je veux vraiment voir lobjet maison, il va falloir que jaille voir o cest indiqu sur le bout de papier. Cest ce que fait le type rfrence, il va voir en mmoire ce quil y a vraiment dans lobjet. Alors que le type valeur pourrait ressembler un billet de banque par exemple. Je peux me balader avec, cest marqu 500 dessus (oui, je suis riche !) et je peux payer directement avec sans que le fait de donner le billet implique daller chercher le contenu la banque. Le type valeur contient la vraie valeur qui en gnral est assez petite et facile stocker. Le type rfrence ne contient quun lien vers un plus gros objet stock ailleurs.

Cette manire diffrente de grer les types et les objets implique plusieurs choses. Dans la mesure o les types valeur possdent vraiment la valeur de ce quon y stocke, une copie de la valeur est effectue chaque fois que lon fait une affectation. Cela est possible car ces types sont relativement petits et optimiss. Cela savre impossible pour un objet qui est trop gros et trop complexe. Cest un peu compliqu de copier toute ma maison alors que cest un peu plus simple de recopier ce quil y a sur le bout de papier . Ainsi, lexemple suivant : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


int a = 5; int b = a; b = 6; Console.WriteLine(a); Console.WriteLine(b);

158/381

affichera les valeurs 5 puis 6. Ce qui est le rsultat que lon attend. En effet, la variable a a t initialise 5. On a ensuite affect a b . La valeur 5 sest copie (duplique) dans la variable b . Puis nous avons affect 6 b .

Ce qui parait tout fait logique. Par contre, lexemple suivant : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Couleur = "Bleue"; Voiture voitureJeremie = voitureNicolas; voitureJeremie.Couleur = "Verte"; Console.WriteLine(voitureNicolas.Couleur); Console.WriteLine(voitureJeremie.Couleur);

affichera verte et verte. Quoi ? Nous indiquons que la voiture de Nicolas est bleue. Puis nous disons que celle de Jrmie est verte et quand on demande dafficher la couleur des deux voitures, on nous dit quelles sont vertes toutes les deux alors quon croyait que celle de Nicolas tait bleue ? Tout lheure, le fait de changer b navait pas chang la valeur de a

Eh oui, ceci illustre le fait que les classes (comme Voiture) sont des types rfrence et ne possdent quune rfrence vers une instance de Voiture. Quand nous affectons voitureNicolas voitureJeremie, nous disons en fait que la voiture de Jrmie rfrence la mme chose que celle de Nicolas. Concrtement, le C# copie la rfrence de l'objet Voiture qui est contenue dans la variable voitureNicolas dans la variable voitureJeremie. Ce sont donc deux variables diffrentes qui possdent tous les deux une rfrence vers l'objet Voiture, qui est la voiture de Nicolas. C'est--dire que les deux variables rfrencent le mme objet. Ainsi, la modification des proprits de lun affectera forcment lautre. Inattendu au premier abord, mais finalement, cest trs logique. Comprendre cette diffrence entre les types valeur et les types rfrence est important, nous verrons dans les chapitres suivants quels sont les autres impacts de cette diffrence. noter galement quil est impossible de driver dun type intgr alors que cest possible de driver facilement dune classe. Dailleurs, si nous parlions un peu dhritage ?

Hritage
Nous avons vu pour linstant la thorie de lhritage. Que les objets chiens hritaient des comportements des objets Animaux, que les labradors hritaient des comportements des chiens, etc. Passons maintenant la pratique et crons une classe Animal et une classe Chien qui en hrite. Nous allons crer des classes relativement courtes et nous nous limiterons dans le nombre dactions ou de proprits de celles-ci. Par exemple, nous pourrions imaginer que la classe Animal possde une proprit NombreDePattes qui est un entier et une mthode Respirer qui affiche le dtail de laction. Ce qui donne :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# public class Animal { public int NombreDePattes { get; set; } public void Respirer() { Console.WriteLine("Je respire"); }

159/381

La classe Chien drive de la classe Animal et peut donc hriter de certains de ses comportements. En loccurrence, la classe Chien hritera de tout ce qui est public ou protg, identifis comme vous le savez dsormais par les mots cls public et protected. Le chien sait galement faire quelque chose qui lui est propre, savoir aboyer. Il possdera donc une mthode supplmentaire. Ce qui donne : Code : C# public class Chien : Animal { public void Aboyer() { Console.WriteLine("Wouaf !"); } }

On reprsente la notion dhritage en ajoutant aprs la classe le caractre : suivi de la classe mre. Ici, nous avons dfini une classe publique Chien qui hrite de la classe Animal. Nous pouvons ds prsent crer des objets Animal et des objets Chien, par exemple : Code : C# Animal animal = new Animal { NombreDePattes = 4 }; animal.Respirer(); Console.WriteLine(); Chien chien = new Chien { NombreDePattes = 4 }; chien.Respirer(); chien.Aboyer();

Si nous excutons ce code, nous aurons :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

160/381

Nous nous rendons bien compte que lobjet Chien, bien que nayant pas dfini la proprit NombreDePattes ou la mthode Respirer() dans le corps de sa classe, est capable davoir des pattes et de faire laction respirer. Il a hrit ces comportements de lobjet Animal, en tous cas, ceux qui sont publiques. Rajoutons deux variables membres de la classe Animal : Code : C# public class Animal { private bool estVivant; public int age; public int NombreDePattes { get; set; } public void Respirer() { Console.WriteLine("Je respire"); }

Lentier age est public alors que le boolen estVivant est priv. Si nous tentons de les utiliser depuis la classe fille Chien, comme ci-dessous : Code : C# public class Chien : Animal { public void Aboyer() { Console.WriteLine("Wouaf !"); } public void Vieillir() { age++; } public void Naissance()

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


age = 0; estVivant = true; // Erreur > 'MaPremiereApplication.Animal.estVivant' // est inaccessible en raison de son niveau de protection } } {

161/381

Nous voyons quil est tout fait possible dutiliser la variable age depuis la mthode Vieillir() alors que lutilisation du boolen estVivant provoque une erreur de compilation. V ous avez bien compris que celui-ci tait inaccessible car il est dfini comme membre priv. Pour lutiliser, on pourra le rendre public par exemple. Il existe par contre un autre mot cl qui permet de rentre des variables/proprits/mthodes inaccessibles depuis un autre objet tout en le rendant accessible depuis des classes filles. Il sagit du mot cl protected. Si nous lutilisons la place de private pour dfinir la visibilit du boolen estVivant, nous pourrons nous rendre compte que la classe Chien peut dsormais compiler : Code : C# public class Animal { protected bool estVivant; [ Extrait de code supprim ] } public class Chien : Animal { [ Extrait de code supprim ] public void Naissance() { age = 0; estVivant = true; // compilation OK }

Par contre, cette variable est toujours inaccessible depuis dautres classes, comme lest galement une variable prive. Dans notre classe Program, linstruction suivante : Code : C# chien.estVivant = true;

provoquera lerreur de compilation que nous connaissons dsormais bien : Code : Console

'MaPremiereApplication.Animal.estVivant' est inaccessible en raison de son niveau de prot

Le mot cl protected prend tout son intrt ds que nous avons faire avec lhritage. Nous verrons un peu plus bas dautres exemples de ce mot cl. Nous avons dit dans lintroduction quun objet B qui drive de lobjet A est une sorte dobjet A. Dans notre exemple du

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


dessus, le Chien est une sorte dAnimal. Cela veut dire que nous pouvons utiliser un chien en tant quanimal. Par exemple, le code suivant : Code : C# Animal animal = new Chien { NombreDePattes = 4 };

162/381

est tout fait correct. Nous disons que notre variable animal, de type Animal est une instance de Chien. Avec cette faon dcrire, nous avons rellement instanci un objet Chien mais celui-ci sera trait en tant quAnimal. Cela veut dire quil sera capable de Respirer() et davoir des pattes. Par contre, mme si en vrai, notre objet serait capable daboyer, le fait quil soit manipul en tant quAnimal nous empche de pouvoir le faire Aboyer. Cela veut dire que le code suivant : Code : C# Animal animal = new Chien { NombreDePattes = 4 }; animal.Respirer(); animal.Aboyer(); // erreur de compilation

provoquera une erreur de compilation pour indiquer que la classe Animal ne contient aucune dfinition pour la mthode Aboyer(). Ce qui est normal, un animal ne sait pas forcment aboyer... Quel est lintrt alors dutiliser le chien en tant quanimal ?

Bonne question. Pour y rpondre, nous allons enrichir notre classe Animal, garder notre classe Chien et crer une classe Chat qui hrite galement dAnimal. Ce pourrait tre : Code : C# public class Animal { protected string prenom; public void Respirer() { Console.WriteLine("Je suis " + prenom + " et je respire"); }

public class Chien : Animal { public Chien(string prenomDuChien) { prenom = prenomDuChien; } public void Aboyer() { Console.WriteLine("Wouaf !"); }

public class Chat : Animal { public Chat(string prenomDuChat)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } prenom = prenomDuChat;

163/381

public void Miauler() { Console.WriteLine("Miaou"); }

Nous forons les chiens et les chats avoir un nom, hrit de la classe Animal, grce au constructeur afin de pouvoir les identifier facilement. Le chat garde le mme principe que le chien, sauf que nous avons une mthode Miauler() la place de la mthode Aboyer() Ce qui est somme toute logique. Lide est de pouvoir utiliser nos chiens et nos chats ensemble comme des animaux, par exemple en utilisant une liste. Pour illustrer ce fonctionnement, donnons vie quelques chiens et quelques chats grce nos pouvoirs de dveloppeur et mettons-les dans une liste : Code : C# List<Animal> animaux = new List<Animal>(); Animal milou = new Chien("Milou"); Animal dingo = new Chien("Dingo"); Animal idefix = new Chien("Idfix"); Animal tom = new Chat("Tom"); Animal felix = new Chat("Flix"); animaux.Add(milou); animaux.Add(dingo); animaux.Add(idefix); animaux.Add(tom); animaux.Add(felix);

Nous avons dans un premier temps instanci une liste danimaux laquelle nous avons rajout 3 chiens et 2 chats, chacun tant considr comme un animal puisquils sont tous des sortes danimaux, grce lhritage. Maintenant, nous navons plus que des animaux dans la liste. Il sera donc possible de les faire tous respirer en une simple boucle : Code : C# foreach (Animal animal in animaux) { animal.Respirer(); }

ce qui donnera :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

164/381

Et voil, cest super simple. Imaginez le bonheur de No sur son arche quand il a compris que grce la POO, il pouvait faire respirer tous les animaux en une seule boucle ! Quel travail conomis. Peu importe ce quil y a dans la liste, des chiens, des chats, des hamsters, nous savons que ce sont tous des animaux et quils savent tous respirer. V ous avez sans doute remarqu que nous faisons la mme chose dans le constructeur de la classe Chien et dans celui de la classe Chat. Deux fois la mme chose Ce nest pas terrible. Peut-tre y a-t-il un moyen de factoriser tout a ? Effectivement, il est possible galement dcrire nos classes de cette faon : Code : C# public class Animal { protected string prenom; public Animal(string prenomAnimal) { prenom = prenomAnimal; } public void Respirer() { Console.WriteLine("Je suis " + prenom + " et je respire"); }

public class Chien : Animal { public Chien(string prenomDuChien) : base(prenomDuChien) { } public void Aboyer() { Console.WriteLine("Wouaf !"); }

public class Chat : Animal { public Chat(string prenomDuChat) : base(prenomDuChat)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } public void Miauler() { Console.WriteLine("Miaou"); }

165/381

Quest-ce qui change ? Eh bien la classe Animal possde un constructeur qui prend en paramtre un prnom et qui le stocke dans sa variable prive. Cest elle qui fait le travail dinitialisation. Il devient alors possible pour les constructeurs des classes filles dappeler le constructeur de la classe mre afin de faire laffectation du prnom. Pour cela, on utilise les deux points suivis du mot cl base qui signifie appelle-moi le constructeur de la classe du dessus auquel nous passons la variable en paramtres. Avec cette criture un peu barbare, il devient possible de factoriser des initialisations qui ont un sens pour toutes les classes filles. Dans notre cas, je veux que tous les objets qui drivent dAnimal puissent facilement dfinir un prnom. Il faut aussi savoir que si nous appelons le constructeur par dfaut dune classe qui n'appelle pas explicitement un constructeur spcialis d'une classe mre, alors celui-ci appellera automatiquement le constructeur par dfaut de la classe dont il hrite. Modifions nouveau nos classes pour avoir : Code : C# public class Animal { protected string prenom; public Animal() { prenom = "Marcel"; } public void Respirer() { Console.WriteLine("Je suis " + prenom + " et je respire"); }

public class Chien : Animal { public void Aboyer() { Console.WriteLine("Wouaf !"); } } public class Chat : Animal { public Chat(string prenomDuChat) { prenom = prenomDuChat; } public void Miauler() { Console.WriteLine("Miaou"); }

Ici, la classe Animal met un prnom par dfaut dans son constructeur. Le chien na pas de constructeur et le chat en a un qui accepte un paramtre.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

166/381

Il est donc possible de crer un Chien sans quil ait de prnom mais il est obligatoire den dfinir un pour le chat. Sauf que lorsque nous instancierons notre objet chien, il appellera automatiquement le constructeur de la classe mre et tous nos chiens sappelleront Marcel : Code : C# static void Main(string[] args) { List<Animal> animaux = new List<Animal>(); Animal chien = new Chien(); Animal tom = new Chat("Tom"); Animal felix = new Chat("Flix"); animaux.Add(chien); animaux.Add(tom); animaux.Add(felix); foreach (Animal animal in animaux) { animal.Respirer(); }

Ce qui donne :

Il est galement possible dappeler un constructeur partir dun autre constructeur. Prenons lexemple suivant : Code : C# public class Voiture { private int vitesse; public Voiture(int vitesseVoiture) { vitesse = vitesseVoiture; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


}

167/381

Si nous souhaitons rajouter un constructeur par dfaut qui initialise la vitesse 10 par exemple, nous pourrons faire : Code : C# public class Voiture { private int vitesse; public Voiture() { vitesse = 10; } public Voiture(int vitesseVoiture) { vitesse = vitesseVoiture; }

Ou encore : Code : C# public class Voiture { private int vitesse; public Voiture() : this(10) { } public Voiture(int vitesseVoiture) { vitesse = vitesseVoiture; }

Ici, lutilisation du mot cl this, suivi dun entier permet dappeler le constructeur qui possde un paramtre entier au dbut du constructeur par dfaut. Inversement, nous pouvons appeler le constructeur par dfaut dune classe depuis un constructeur possdant des paramtres afin de pouvoir bnficier des initialisations de celui-ci : Code : C# public class Voiture { private int vitesse; private string couleur; public Voiture() { vitesse = 10; } public Voiture(string couleurVoiture) : this() { couleur = couleurVoiture;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} }

168/381

Puisque nous sommes parler dhritage, il faut savoir que tous les objets que nous crons ou qui sont disponibles dans le framework .NET hritent dun objet de base. On parle en gnral dun super objet . Lintrt de driver dun tel objet est de permettre tous les objets davoir certains comportements en commun, mais galement de pouvoir ventuellement tous les traiter en tant quobjet. Notre super objet est reprsent par la classe Object qui dfinit plusieurs mthodes. V ous les avez dj vues si vous avez regard dans la compltion automatique aprs avoir cr un objet. Prenons une classe toute vide, par exemple : Code : C# public class ObjetVide { }

Si nous instancions cet objet et que nous souhaitons lutiliser, nous verrons que la compltion automatique nous propose des mthodes que nous navons jamais cres :

Nous voyons plusieurs mthodes, comme la mthode Equals ou GetHashCode ou GetType ou encore ToString. Comme vous lavez compris, ce sont des mthodes qui sont dfinies dans la classe Object. La mthode ToString par exemple permet dobtenir une reprsentation de lobjet sous la forme dune chaine de caractres. Cest une mthode qui va souvent nous servir, nous y reviendrons un peu plus tard. Ce super-objet est du type Object, mais on utilise gnralement son alias object. Ainsi, il est possible dutiliser tous nos objets comme des object et ainsi utiliser les mthodes qui sont dfinies sur la classe Object. Ce qui nous permet de faire : Code : C# static void Main(string[] args) { ObjetVide monObjetVide = new ObjetVide(); Chien chien = new Chien(); int age = 30; string prenom = "Nicolas"; AfficherRepresentation(monObjetVide); AfficherRepresentation(chien); AfficherRepresentation(age); AfficherRepresentation(prenom);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} private static void AfficherRepresentation(object monObjetVide) { Console.WriteLine(monObjetVide.ToString()); }

169/381

Ce qui donne :

Comme indiqu, la mthode ToString() permet dafficher la reprsentation par dfaut dun objet. V ous aurez remarqu quil y a une diffrence suivant ce que nous passons. En effet, la reprsentation par dfaut des types rfrence correspond au nom du type, savoir son espace de nom suivi du nom de sa classe. Pour ce qui est des types valeur, il contient en gnral la valeur du type, lexception des structures que nous navons pas encore vues et que nous aborderons un peu plus loin. Lintrt dans cet exemple de code est de voir que nous pouvons manipuler tout comme un object. Dune manire gnrale, vous aurez peu loccasion de traiter vos objets en tant quobject car il est vraiment plus intressant de profiter pleinement du type, lobject tant peu utilisable. Notez que lhritage de object est automatique. Nul besoin dutiliser la syntaxe dhritage que nous avons dj vue.

Jen profite maintenant que vous connaissez la mthode ToString() pour parler dun point qui a peut-tre titill vos cerveaux. Dans la premire partie, nous avions fait quelque chose du genre : Code : C# int vitesse = 20; string chaine = "La vitesse est " + vitesse + " km/h";

La variable vitesse est un entier. La chane La vitesse est est une chaine de caractres. Nous essayons dajouter un entier une chane alors que jai dit quils ntaient pas compatibles entre eux ! Et pourtant cela fonctionne. Effectivement, cest bizarre. Nous concatnons une chane un entier avec loprateur + et nous concatnons encore une chane.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Et si je fais linverse : Code : C# int vitesse = 20 + "40";

170/381

cela provoque une erreur de compilation. Cest logique, on ne peut pas ajouter un entier et une chane de caractres. Alors pourquoi cela fonctionne dans lautre sens ? Ce quil se passe en fait dans linstruction : Code : C# string chaine = "La vitesse est " + vitesse + " km/h";

cest que le compilateur se rend compte que nous concatnons une chane avec un autre objet, peu importe que ce soit un entier ou un objet complexe. Alors pour que a fonctionne, il demande une reprsentation de lobjet sous la forme dune chane de caractres. Nous avons vu que ceci se faisait en appelant la mthode ToString() qui est hrite de lobjet racine Object. Linstruction est donc quivalente : Code : C# string chaine = "La vitesse est " + vitesse.ToString() + " km/h";

Dans le cas dun type valeur comme un entier, la mthode ToString() renvoie la reprsentation interne de la valeur, savoir "20". Dans le cas dun objet complexe, elle aurait renvoy le nom du type de lobjet. Avant de terminer, il est important dindiquer que le C# nautorise pas lhritage multiple. Ainsi, si nous possdons une classe Carnivore et une classe EtreVivant, il ne sera pas possible de faire hriter directement un objet Homme de lobjet Carnivore et de lobjet EtreVivant. Ainsi, le code suivant : Code : C# public class Carnivore { } public class EtreVivant { } public class Homme : Carnivore, EtreVivant { }

provoquera lerreur de compilation suivante : Code : Console

La classe 'MaPremiereApplication.Homme' ne peut pas avoir plusieurs classes de base : 'Ma

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

171/381

Il est impossible de driver de deux objets en mme temps.

Si par contre, cela est pertinent, nous pourrons faire un hritage en cascade afin que Carnivore drive de EtreVivant et que Homme drive de Carnivore : Code : C# public class Carnivore : EtreVivant { } public class EtreVivant { } public class Homme : Carnivore { }

Cependant, il nest pas toujours pertinent d'oprer de la sorte. Notre Homme pourrait tre la fois Carnivore et Frugivore, cependant cela na pas de sens quun carnivore soit galement frugivore, ou linverse. Oui mais tu as dit que chaque objet drivait du super objet Object, sil drive dune autre classe comme un chien drive dun animal, a fait bien deux classes dont il drive

Effectivement, mais dans ce cas-l, ce nest pas pareil. Comme il est automatique de driver de object, cest comme si on avait le chien qui hrite de animal qui hrite lui-mme de object. Le C# est assez malin pour a.

Substitution
Nous avons vu juste avant lutilisation de la mthode ToString() qui permet dobtenir la reprsentation dun objet sous forme de chaine de caractres. En loccurrence, vous conviendrez avec moi que la reprsentation de notre classe Chien nest pas particulirement exploitable. Le nom du type cest bien, mais ce nest pas trs parlant. a serait pas mal que quand nous demandons dafficher un chien, nous obtenions le nom du chien, vous ne trouvez pas ? Cest l quintervient la substitution. Nous en avons parl dans lintroduction la POO, la substitution permet de redfinir un comportement dont lobjet a hrit afin quil corresponde aux besoins de lobjet fils. Typiquement, ici, la mthode ToString() du super-objet ne nous convient pas et dans le cas de notre chien, nous souhaitons la redfinir, en crire une nouvelle version. Pour cet exemple, simplifions notre classe Chien afin quelle nait quune proprit pour stocker son prnom : Code : C# public class Chien { public string Prenom { get; set; } }

Pour redfinir la mthode ToString() nous allons devoir utiliser le mot cl override qui signifie que nous souhaitons substituer la mthode existante afin de remplacer son comportement, ce que nous pourrons crire en C# avec : Code : C# public class Chien {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public string Prenom { get; set; } public override string ToString() { return "Je suis un chien et je m'appelle " + Prenom; }

172/381

Le mot cl override se met avant le type de retour de la mthode, comme on peut le voir ci-dessus. Si nous appelons dsormais la mthode ToString de notre objet Chien : Code : C# Chien chien = new Chien { Prenom = "Max" }; Console.WriteLine(chien.ToString());

notre programme va utiliser la nouvelle version de la mthode ToString() et nous aurons :

Et voil un bon moyen dutiliser la substitution, la reprsentation de notre objet est quand mme plus parlante. Adaptons dsormais cet exemple nos classes. Pour montrer comment faire, reprenons notre classe Chien qui possde une mthode Aboyer() : Code : C# public class Chien { public void Aboyer() { Console.WriteLine("Wouaf !"); } }

Nous pourrions imaginer crer une classe ChienMuet qui drive de la classe Chien et qui hrite donc de ses comportements.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Mais, que penser dun chien muet qui serait capable daboyer ? Cela na pas de sens ! Il faut donc redfinir cette fichue mthode. Utilisons alors le mot cl override comme nous lavons vu pour obtenir : Code : C# public class ChienMuet : Chien { public override void Aboyer() { Console.WriteLine("..."); } }

173/381

Crons un chien muet puis faisons-le aboyer, cela donne : Code : C# ChienMuet pauvreChien = new ChienMuet(); pauvreChien.Aboyer();

Sauf que nous rencontrons un problme. Si nous tentons de compiler ce code, Visual C# express nous gnre une erreur de compilation : Code : Console

'MaPremiereApplication.Program.ChienMuet.Aboyer()' : ne peut pas substituer le membre hr

En ralit, pour pouvoir crer une mthode qui remplace une autre, il faut quune condition supplmentaire soit vrifie : il faut que la mthode remplacer sannonce comme candidate la substitution. Cela veut dire que lon ne peut pas substituer nimporte quelle mthode, mais seulement celles qui acceptent de ltre. Cest le cas pour la mthode ToString que nous avons vue prcdemment. Les concepteurs du framework .NET ont autoris cette ventualit. Heureusement, sinon, nous serions bien embts . Pour marquer notre mthode Aboyer de la classe Chien comme candidate ventuelle la substitution, il faut la prfixer du mot cl virtual. Ainsi, elle annonce ses futures filles que si elles le souhaitent, elles peuvent redfinir cette mthode. Cela se traduit ainsi dans le code : Code : C# public class Chien { public virtual void Aboyer() { Console.WriteLine("Wouaf !"); } } public class ChienMuet : Chien { public override void Aboyer() { Console.WriteLine("..."); } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

174/381

Dsormais, linstanciation de lobjet est possible et nous pourrons avoir notre code : Code : C# ChienMuet pauvreChien = new ChienMuet(); pauvreChien.Aboyer();

qui affichera :

Parfait ! Tout est rentr dans lordre. Le message derreur, quoique peu explicite, nous mettait quand mme sur la bonne voie. Visual C# express nous disait quil fallait que la mthode soit marque comme virtual, ce que nous avons fait. Il proposait galement quelle soit marque abstract, nous verrons un peu plus loin ce que a veut dire. Visual C# express indiquait enfin que la mthode pouvait tre marque override. Cela veut dire quune classe fille de ChienMuet peut galement redfinir la mthode Aboyer() afin quelle colle ses besoins. Elle nest pas marque virtual mais elle est marque override. Par exemple : Code : C# public class ChienMuetAvecSyntheseVocale : ChienMuet { public override void Aboyer() { Console.WriteLine("bwarf !"); } }

Il y a encore un dernier point que nous navons pas abord. Il sagit de la capacit pour une classe fille de redfinir une mthode tout en conservant la fonctionnalit de la mthode de la classe mre. Imaginons notre classe Animal qui possde une mthode Manger() :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# public class Animal { public virtual void Manger() { Console.WriteLine("Mettre les aliments dans la bouche"); Console.WriteLine("Mastiquer"); Console.WriteLine("Avaler"); Console.WriteLine("..."); } }

175/381

Notre classe Chien pourra sappuyer sur le comportement de la mthode Manger() de la classe Animal pour crer sa propre action personnelle. Cela se passe en utilisant nouveau le mot cl base qui reprsente la classe mre. Nous pourrons par exemple appeler la mthode Manger() de la classe mre afin de rutiliser son fonctionnement. Cela donne : Code : C# public class Chien : Animal { public override void Manger() { Console.WriteLine("Rclamer manger au matre"); base.Manger(); Console.WriteLine("Remuer la queue"); } }

Dans cet exemple, je fais quelque chose avant dappeler la mthode de la classe mre, puis je fais quelque chose dautre aprs. Maintenant, si nous faisons manger notre chien : Code : C# Chien chien = new Chien(); chien.Manger();

nous aurons :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

176/381

Nous voyons bien avec cet exemple comment la classe fille peut rutiliser les mthodes de sa classe mre. A noter qu'on peut galement parler de spcialisation ou de redfinition la place de la substitution.

Polymorphisme
Nous avons dit quune manifestation du polymorphisme tait la capacit d'une classe effectuer la mme action sur diffrents types dintervenants. Il s'agit de la surcharge, appel aussi polymorphisme ad hoc. Concrtement, cela veut dire quil est possible de dfinir la mme mthode avec des paramtres en entre diffrents. Si vous vous rappelez bien, cest quelque chose que nous avons dj fait sans le savoir. Devinez Oui, cest a, avec la mthode Console.WriteLine. Nous avons pu afficher des chaines de caractres, mais aussi des entiers, mme des types double, et plus rcemment des objets. Comment est-ce possible alors que nous avons dj vu quil tait impossible de passer des types en paramtres dune mthode qui ne correspondent pas sa signature ? Ainsi, lexemple suivant : Code : C# public class Program { static void Main(string[] args) { Math math = new Math(); int a = 5; int b = 6; int resultat = math.Addition(a, b); double c = 1.5; double d = 5.0; resultat = math.Addition(c, d); // erreur de compilation

public class Math { public int Addition(int a, int b) { return a + b;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} }

177/381

provoquera une erreur de compilation lorsque nous allons essayer de passer des variables du type double notre mthode qui prend des entiers en paramtres. Pour que ceci fonctionne, nous allons rendre polymorphe cette mthode en dfinissant nouveau cette mme mthode mais en lui faisant prendre des paramtres dentres diffrents : Code : C# public class Program { static void Main(string[] args) { Math math = new Math(); int a = 5; int b = 6; int resultat = math.Addition(a, b); double c = 1.5; double d = 5.0; double resultatDouble = math.Addition(c, d); // ca compile,

youpi } }

public class Math { public int Addition(int a, int b) { return a + b; } public double Addition(double a, double b) { return a + b; }

Nous avons ainsi crit deux formes diffrentes de la mme mthode. Une qui accepte des entiers et lautre qui accepte des double. Ce code fonctionne dsormais correctement. Il est bien sr possible dcrire cette mthode avec beaucoup de paramtres de types diffrents, mme une classe Chien, en imaginant que le fait dadditionner 2 chiens corresponde au fait dadditionner leur nombre de pattes : Code : C# public class Math { public int Addition(int a, int b) { return a + b; } public double Addition(double a, double b) { return a + b; } public int Addition(Chien c1, Chien c2) {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} return c1.NombreDePattes + c2.NombreDePattes;

178/381

Attention, jai toujours indiqu quil tait possible dajouter une nouvelle forme la mme mthode en changeant les paramtres dentre. V ous ne pourrez pas le faire en changeant uniquement le paramtre de retour. Ce qui fait que cet exemple ne pourra pas compiler : Code : C# public class Math { public int Addition(int a, int b) { return a + b; } public double Addition(int a, int b) { return a + b; }

Les deux mthodes acceptent deux entiers en paramtres et renvoient soit un entier, soit un double. Le compilateur ne sera pas capable de choisir quelle mthode utiliser lorsque nous essayerons dappeler cette mthode. Les mthodes doivent se diffrencier avec les paramtres dentre. Lorsque nous avons plusieurs signatures possibles pour la mme mthode, vous remarquerez que la compltion automatique nous propose alors plusieurs alternatives :

Visual C# Express nous indique quil a trois mthodes possibles qui sappellent Math.Addition. Pour voir la signature des autres mthodes, il suffit de cliquer sur les flches, ou dutiliser les flches du clavier :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

179/381

Cest ce quil se passe dans la mthode Console.WriteLine :

Nous voyons ici quil existe 19 critures de la mthode WriteLine, la cinquime prenant en paramtres un dcimal. Notez que pour crire plusieurs formes de cette mthode, nous pouvons galement jouer sur le nombre de paramtres. La mthode : Code : C# public int Addition(int a, int b, int c) { return a + b + c; }

sera bien une nouvelle forme de la mthode Addition. Nous avons galement vu dans le chapitre sur les constructeurs dune classe quil tait possible de cumuler les constructeurs avec des paramtres diffrents. Il sagit nouveau du polymorphisme. Il nous permet de dfinir diffrents constructeurs sur nos objets.

La conversion entre les objets avec le casting


Nous avons dj vu dans la partie prcdente quil tait possible de convertir les types qui se ressemblent entre eux. Cela fonctionne galement avec les objets. Plus prcisment, cela veut dire que nous pouvons convertir un objet en un autre seulement sil est une sorte de lautre objet. Nous avons vu dans les chapitres prcdents quil sagissait de la notion dhritage. Ainsi, si nous avons dfini une classe Animal et que nous dfinissons une classe Chien qui hrite de cette classe Animal : Code : C# public class Animal { } public class Chien : Animal { }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

180/381

nous pourrons alors convertir le chien en animal dans la mesure o le chien est une sorte danimal : Code : C# Chien medor = new Chien(); Animal animal = (Animal)medor;

Nous utilisons pour ce faire un cast, comme nous lavons dj fait pour les types intgrs (int, bool, etc.). Il suffit de prfixer la variable convertir du type entre parenthses dans lequel nous souhaitons le convertir. Ici, nous pouvons convertir facilement notre Chien en Animal. Par contre, il est impossible de convertir un chien en voiture, car il ny a pas de relation dhritage entre les deux. Ainsi les instructions suivantes : Code : C# Chien medor = new Chien(); Voiture voiture = (Voiture)medor;

provoqueront une erreur de compilation. Nous avons prcdemment utilis lhritage afin de mettre des chiens et des chats dans une liste danimaux. Nous avions fait quelque chose du genre : Code : C# List<Animal> animaux = new List<Animal>(); Animal chien = new Chien(); Animal chat = new Chat(); animaux.Add(chien); animaux.Add(chat);

Il serait plus logique en fait dcrire les instructions suivantes : Code : C# List<Animal> animaux = new List<Animal>(); Chien chien = new Chien(); Chat chat = new Chat(); animaux.Add((Animal)chien); animaux.Add((Animal)chat);

Dans ce cas, nous crons un objet Chien et un objet Chat que nous mettons dans une liste dobjets Animal grce une conversion utilisant un cast. En fait, ce cast est inutile et nous pouvons simplement crire : Code : C# List<Animal> animaux = new List<Animal>(); Chien chien = new Chien(); Chat chat = new Chat();

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


animaux.Add(chien); animaux.Add(chat);

181/381

La conversion est implicite, comme lorsque nous avions utilis un object en paramtres dune mthode et que nous pouvions lui passer tous les types qui drivent d object. Nous avions galement vu que nous ne pouvions traiter les chiens et les chats que comme des animaux partir du moment o nous les mettions dans une liste. Avec les objets suivants : Code : C# public class Animal { public void Respirer() { Console.WriteLine("Je respire"); } } public class Chien : Animal { public void Aboyer() { Console.WriteLine("Waouf"); } } public class Chat : Animal { public void Miauler() { Console.WriteLine("Miaou"); } }

Nous pouvions utiliser une boucle pour faire respirer tous nos animaux : Code : C# List<Animal> animaux = new List<Animal>(); Chien chien = new Chien(); Chat chat = new Chat(); animaux.Add(chien); animaux.Add(chat); foreach (Animal animal in animaux) { animal.Respirer(); }

Mais impossible de faire aboyer le chien, ni miauler le chat. Si vous tentez de remplacer dans la boucle Animal par Chien, avec : Code : C# foreach (Chien c in animaux) { c.Aboyer();

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


}

182/381

V ous pourrez faire aboyer le premier lment de la liste qui est effectivement un chien, par contre il y aura un plantage au deuxime lment de la liste car il sagit dun chat :

Lorsque notre programme a tent de convertir un animal qui est un chat en chien, il nous a fait comprendre quil napprciait que moyennement. Les chiens naiment pas trop les chats dune manire gnrale, alors en plus, un chat qui essaie de se faire passer pour un chien : cest une dclaration de guerre ! V pourquoi notre programme a lev une exception. Il lui tait impossible de convertir un Chat en Chien. oil Il est cependant possible de tester si une variable correspond un objet grce au mot-cl is. Ce qui nous permettra de faire la conversion adquate et de nous viter une erreur lexcution : Code : C# foreach (Animal animal in animaux) { if (animal is Chien) { Chien c = (Chien)animal; c.Aboyer(); } if (animal is Chat) { Chat c = (Chat)animal; c.Miauler(); } }

Nous testons avec le mot-cl is si lanimal est une instance dun Chien ou dun chat. Le code du dessus nous permettra dutiliser dans la boucle lanimal courant comme un chien ou un chat en fonction de ce quil est vraiment, grce au test. Ce qui produira :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

183/381

Le fait de tester ce quest vraiment lanimal avant de le convertir est une scurit indispensable pour viter le genre derreur du dessus. Cest linconvnient du cast explicite. Il convient trs bien si nous sommes certains du type dans lequel nous souhaitons en convertir un autre. Par contre, si la conversion nest pas possible, alors nous aurons une erreur. Lorsque nous ne sommes pas certains du rsultat du cast, mieux vaut tester si linstance dun objet correspond bien lobjet luimme. Cela peut se faire comme nous lavons vu avec le mot-cl is, mais galement avec un autre cast qui sappelle le cast dynamique. Il se fait en employant le mot-cl as. Ce cast dynamique vrifie que lobjet est bien convertible. Si cest le cas, alors il fait un cast explicite pour renvoyer le rsultat de la conversion, sinon, il renvoie une rfrence nulle. Le code du dessus peut donc scrire : Code : C# foreach (Animal animal in animaux) { Chien c1 = animal as Chien; if (c1 != null) { c1.Aboyer(); } Chat c2 = animal as Chat; if (c2 != null) { c2.Miauler(); } }

On utilise le mot-cl as en le faisant prcder de la valeur tenter de convertir et en le faisant suivre du type dans lequel nous souhaitons la convertir. Fonctionnellement, nous faisons la mme chose dans les deux codes. V ous pouvez choisir lcriture que vous prfrez, mais sachez que cest ce dernier qui est en gnral utilis car il est prconis par Microsoft et est un tout petit peu plus performant. Un petit dtail encore. Il est possible de convertir un type valeur, comme un int ou un string en type rfrence en utilisant ce quon appelle le boxing. Rien voir avec le fait de taper sur les types valeur. Comme nous lavons vu, les types valeur et les types rfrence sont grs diffremment par .NET. Aussi, si nous convertissons un type valeur en type rfrence, .NET fait une

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


opration spciale automatiquement. Ainsi le code suivant : Code : C# int i = 5; object o = i; // boxing

184/381

effectue un boxing automatique de lentier en type rfrence. Cest ce boxing automatique qui nous permet de manipuler les types valeur comme des object. Cest aussi ce qui nous a permis plus haut de passer un entier en paramtre une mthode qui acceptait un object. En interne, ce quil se passe cest que object se voit attribuer une rfrence vers une copie de la valeur de i. Ainsi, modifier o ne modifiera pas i. Ce code : Code : C# int i = 5; object o = i; // boxing o = 6; Console.WriteLine(i); Console.WriteLine(o);

affiche 5 puis 6. Le contraire est galement possible, ce quon appelle lunboxing. Seulement, celui-ci a besoin dun cast explicite afin de pouvoir compiler. C'est--dire : Code : C# int i = 5; object o = i; // boxing int j = (int)o; // unboxing

ici nous reconvertissons la rfrence vers la valeur de o en entier et nous effectuons nouveau une copie de cette valeur pour la mettre dans j. Ainsi le code suivant : Code : C# int i = 5; object o = i; // boxing o = 6; int j = (int)o; // unboxing j = 7; Console.WriteLine(i); Console.WriteLine(o); Console.WriteLine(j);

affichera en toute logique 5 puis 6 puis 7. noter que ces oprations sont chronophages, elles sont donc faire le moins possible.

En rsum

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

185/381

Les objets peuvent tre des types valeur ou des types rfrence. Les variables de type valeur possdent la valeur de l'objet, comme un entier. Les variables de type rfrence possdent une rfrence vers l'objet en mmoire. Tous les objets drivent de la classe de base Object. On peut substituer une mthode grce au mot-cl override si elle s'est dclare candidate la substitution grce au mot-cl virtual. La surcharge est le polymorphisme permettant de faire varier les types des paramtres d'une mme mthode ou leurs nombres. Il est possible grce au cast de convertir un type en un autre type, s'ils ont une relation d'hritage.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

186/381

Notions avances de POO en C#


Dans ce chapitre, nous allons continuer dcouvrir comment nous pouvons faire de l'orient objet avec le C#. Nous allons pousser un peu plus loin en dcouvrant les interfaces et en manipulant les classes statiques et abstraites. la fin de ce chapitre, vous serez capables de faire des objets encore plus volus et vous devriez tre capables de crer un vrai petit programme orient objet !

Comparer des objets


Nous avons vu dans la premire partie quil tait possible de comparer facilement des types valeur grce aux oprateurs de comparaison. En effet, vu que des variables de ces types possdent directement la valeur que nous lui affectons, on peut facilement comparer un entier avec la valeur 5, ou un entier avec un autre entier. Par contre, cela ne fonctionne pas avec les objets. En effet, nous avons vu que les variables qui reprsentent des instances dobjet contiennent en fait une rfrence vers linstance. Cela na pas vraiment de sens de comparer des rfrences. De plus, en imaginant que je veuille vraiment comparer deux voitures, sur quels critres puis-je dterminer quelles sont gales ? La couleur ? La vitesse ? Sans rien faire, la comparaison en utilisant par exemple loprateur dgalit == permet simplement de vrifier si les rfrences pointent vers le mme objet. Pour les exemples suivants, nous nous baserons sur la classe V oiture suivante : Code : C# public class Voiture { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } }

Ainsi, si nous crivons : Code : C# Voiture voitureNicolas = new Voiture(); voitureNicolas.Couleur = "Bleue"; Voiture voitureJeremie = voitureNicolas; voitureJeremie.Couleur = "Verte"; if (voitureJeremie == voitureNicolas) { Console.WriteLine("Les objets rfrencent la mme instance"); }

Ce code affichera la chaine Les objets rfrencent la mme instance car effectivement, nous avons affect la rfrence de voitureNicolas voitureJeremie. (Ce qui implique galement que la modification de la voiture de Jrmie affecte galement la voiture de Nicolas, comme nous lavons dj vu). Par contre, le code suivant : Code : C# Voiture voitureNicolas = new Voiture(); Voiture voitureJeremie = new Voiture(); if (voitureJeremie == voitureNicolas) { Console.WriteLine("Les objets rfrencent la mme instance"); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

187/381

n'affichera videmment rien car ce sont deux instances diffrentes. Sil savre quil est vraiment pertinent de pouvoir comparer deux voitures entre elles, il faut savoir que cest quand mme possible. La premire chose faire est de dfinir les critres de comparaison. Par exemple, nous navons qu dire que deux voitures sont identiques quand la couleur, la marque et la vitesse sont gales. Je sais, cest un peu irrel, mais cest pour lexemple. Ainsi, nous pourrons par exemple vrifier que deux voitures sont gales avec linstruction suivante : Code : C# if (voitureNicolas.Couleur == voitureJeremie.Couleur && voitureNicolas.Marque == voitureJeremie.Marque && voitureNicolas.Vitesse == voitureJeremie.Vitesse) { Console.WriteLine("Les deux voitures sont identiques"); }

La comparaison dgalit entre deux objets, cest en fait le rle de la mthode Equals() dont chaque objet hrite de la classe mre Object. A part pour les types valeur, le comportement par dfaut de la mthode Equals() est de comparer les rfrences des objets. Seulement, il est possible de dfinir un comportement plus appropri pour notre classe V oiture, grce la fameuse spcialisation. Comme on la dj vu, on utilise le mot cl override. Ceci est possible dans la mesure o la classe Object a dfini la mthode Equals comme virtuelle, avec le mot cl virtual. Ce qui donne : Code : C# public class Voiture { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } public override bool Equals(object obj) { Voiture v = obj as Voiture; if (v == null) return false; return Vitesse == v.Vitesse && Couleur == v.Couleur && Marque == v.Marque; } }

Remarquons que la mthode Equals prend en paramtre un object. La premire chose faire est donc de vrifier que nous avons rellement une voiture, grce au cast dynamique. Ensuite, il ne reste qu comparer les proprits de linstance courante et de lobjet pass en paramtre. Pour faire une comparaison entre deux voitures, nous pourrons utiliser le code suivant : Code : C# Voiture voitureNicolas = new Voiture { Vitesse = 10, Marque = "Peugeot", Couleur = "Grise"}; Voiture voitureJeremie = new Voiture { Vitesse = 10, Marque = "Peugeot", Couleur = "Grise" }; if (voitureNicolas.Equals(voitureJeremie)) {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Console.WriteLine("Les objets ont les mmes valeurs dans leurs proprits"); }

188/381

Nos deux voitures sont identiques car leurs marques, leurs couleurs et leurs vitesses sont identiques :

Facile de comparer . Sauf que vous aurez peut-tre remarqu que la compilation de ce code provoque un avertissement. Il ne sagit pas dune erreur, mais Visual C# express nous informe quil faut faire attention :

Il nous dit que nous avons substitu la mthode Equals() sans avoir redfini la mthode GetHashCode(). Nous n'avons pas besoin ici de savoir quoi sert vraiment la mthode GetHashCode(), mais si vous voulez en savoir plus, n'hsitez pas consulter la documentation. Toujours est-il que nous devons rajouter une spcialisation de la mthode GetHashCode(), dont le but est de renvoyer un identifiant plus ou moins unique reprsentant l'objet, ce qui donnera : Code : C# public class Voiture { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } public override bool Equals(object obj) { Voiture v = obj as Voiture;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


if (v == null) return false; return Vitesse == v.Vitesse && Couleur == v.Couleur && Marque == v.Marque; } public override int GetHashCode() { return Couleur.GetHashCode() * Marque.GetHashCode() * Vitesse.GetHashCode(); } }

189/381

Nous nous servons du fait que chaque variable de la classe possde dj un identifiant obtenu avec la mthode GetHashCode(). En combinant chaque identifiant de chaque proprit nous pouvons en crer un nouveau. Ici, la classe est complte et prte tre compare. Elle pourra donc fonctionner correctement avec tous les algorithmes dgalit du framework .NET. Notez quand mme que devoir substituer ces deux mthodes est une opration relativement rare, nous lavons tudi pour la culture. Ce qui est important retenir cest ce fameux warning. La conclusion tirer est que notre faon de comparer, bien que fonctionnelle pour notre voiture, nest pas parfaite. Pourquoi ? Parce quen ayant substitu la mthode Equals(), nous croyons que la comparaison est bonne sauf que le compilateur nous apprend que ce nest pas le cas. Heureusement quil tait l ce compilateur. Comme cest une erreur classique, il est capable de la dtecter. Mais si cest autre chose et quil ne le dtecte pas ? Cela manque dune uniformisation tout a, vous ne trouvez pas ? Il faudrait quelque chose qui nous assure que la classe est correctement comparable. Une espce de contrat que lobjet sengagerait respecter pour tre sr que toutes les comparaisons soient valides. Un contrat ? Un truc qui finit par able ? a me rappelle quelque chose a. Mais oui, les interfaces.

Les interfaces
Une fois nest pas coutume, plutt que de commencer par tudier le plus simple, nous allons tudier le plus logique puis nous reviendrons sur le plus simple. Cest--dire que nous allons pousser un peu plus loin la comparaison en nous servant des interfaces et nous reviendrons ensuite sur comment crer une interface. Nous avons donc dit que les interfaces taient un contrat que sengageait respecter un objet. Cest tout fait ce dont on a besoin ici. Notre objet doit sengager fonctionner pour tous les types de comparaison. Il doit tre comparable. Mais comparable ne veut pas forcment dire gal , nous devrions tre aussi capables dindiquer si un objet est suprieur un autre. Pourquoi ? Imaginons que nous possdions un tableau de voitures et que nous souhaitions le trier comme on a vu dans un chapitre prcdent. Pour les entiers ctait une opration plutt simple, avec la mthode Array.Sort() ils taient automatiquement tris par ordre croissant. Mais dans notre cas, comment un tableau sera capable de trier nos voitures ? Nous voici donc en prsence dun cas concret dutilisation des interfaces. Linterface IComparable permet de dfinir un contrat de mthodes destines la prise en charge de la comparaison entre deux instances dun objet. Une fois ces mthodes implmentes, nous serons certains que nos objets seront comparables correctement. Pour cela, nous allons faire en sorte que notre classe implmente linterface. Reprenons notre classe Voiture avec uniquement ses proprits et faisons lui implmenter linterface IComparable. Pour implmenter une interface, on utilisera la mme syntaxe que pour hriter dune classe, c'est--dire quon utilisera les deux points suivis du type de linterface. Ce qui donne : Code : C# public class Voiture : IComparable { public string Couleur { get; set; } public string Marque { get; set; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} public int Vitesse { get; set; }

190/381

Il est conventionnel de dmarrer le nom dune interface par un I majuscule. Cest le cas de toutes les interfaces du framework .NET.

Si vous tentez de compiler ce code, vous aurez le message derreur suivant :

Le compilateur nous rappelle lordre : nous annonons que nous souhaitons respecter le contrat de comparaison, sauf que nous navons pas la mthode adquate ! Eh oui, le contrat indique ce que nous nous engageons faire mais pas la faon de le faire. Limplmentation de la mthode est notre charge. Toujours dans loptique de simplifier la tche du dveloppeur, Visual C# Express nous aide pour implmenter les mthodes dun contrat. Faites un clic droit sur linterface et choisissez dans le menu contextuel Implmenter linterface et Implmenter linterface :

Visual C# Express nous gnre le code suivant : Code : C# public class Voiture : IComparable { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } public int CompareTo(object obj) { throw new NotImplementedException(); }

C'est--dire la signature de la mthode quil nous manque pour respecter le contrat de linterface et un contenu que nous ne comprenons pas pour linstant. Nous y reviendrons plus tard, pour linstant, vous navez qu supprimer la ligne : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

191/381

throw new NotImplementedException();

Il ne reste plus qu crire le code de la mthode. Pour ce faire, il faut dfinir un critre de tri. Trier des voitures na pas trop de sens, aussi nous dirons que nous souhaitons les trier suivant leurs vitesses. Pour respecter correctement le contrat, nous devons respecter la rgle suivante qui se trouve dans la documentation de la mthode de linterface : Si une voiture est infrieure une autre, alors nous devons renvoyer une valeur infrieure 0, disons -1. Si elle est gale, alors nous devons renvoyer 0. Enfin, si elle est suprieure, nous devons renvoyer une valeur suprieure 0, disons 1.

Ce qui donne : Code : C# public int CompareTo(object obj) { Voiture voiture = (Voiture)obj; if (this.Vitesse < voiture.Vitesse) return -1; if (this.Vitesse > voiture.Vitesse) return 1; return 0; }

noter que la comparaison seffectue entre lobjet courant et un objet qui lui est pass en paramtres. Pour que ce soit un peu plus clair, jai utilis le mot-cl this qui permet de bien identifier lobjet courant et lobjet pass en paramtres. Comme il est facultatif, nous pouvons le supprimer. V ous aurez galement remarqu que jutilise un cast explicite avant de comparer. Ceci permet de renvoyer une erreur si jamais lobjet comparer nest pas du bon type. En effet, que devrais-je renvoyer si jamais lobjet quon me passe nest pas une voiture ? Une erreur, cest trs bien. Le code est suffisamment explicite pour que nous comprenions facilement ce que lon doit faire : comparer les vitesses. Il est possible de simplifier grandement le code car pour comparer nos deux voitures, nous effectuons la comparaison sur la valeur dun entier, ce qui est plutt trivial. Dautant plus que lentier, en bon objet comparable, possde galement la mthode CompareTo(). Ce qui fait quil est possible dcrire notre mthode de comparaison de cette faon : Code : C# public int CompareTo(object obj) { Voiture voiture = (Voiture)obj; return Vitesse.CompareTo(voiture.Vitesse); }

En effet, Vitesse tant un type intgr, il implmente dj correctement la comparaison. Cest dailleurs pour a que le tableau dentier que nous avons vu prcdemment a t capable de se trier facilement. En ayant implment cette interface, nous pouvons dsormais trier des tableaux de Voiture :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# Voiture[] voitures = new Voiture[] { new Voiture { Vitesse = 100 }, new Voiture { Vitesse = 40 }, new Voiture { Vitesse = 10 }, new Voiture { Vitesse = 40 }, new Voiture { Vitesse = 50 } }; Array.Sort(voitures); foreach (Voiture v in voitures) { Console.WriteLine(v.Vitesse); }

192/381

Ce qui donne :

V pour le tri, mais si je peux me permettre, je trouve que ce code-l est un peu moche. oil Jy reviendrai un peu plus tard. Nous avons donc implment notre premire interface. Finalement, ce ntait pas si compliqu. V oyons prsent comment crer nos propres interfaces. Une interface se dfinit en C# comme une classe, sauf quon utilise le mot-cl interface la place de class. En tant que dbutant, vous aurez rarement besoin de crer des interfaces. Cependant, il est utile de savoir le faire. Par contre, il sera beaucoup plus frquent que vos classes implmentent des interfaces existantes du framework .NET, comme nous venons de le faire. V oyons prsent comment crer une interface et examinons le code suivant : Code : C# public interface IVolant { int NombrePropulseurs { get; set; } void Voler(); }

Note : comme une classe, il est recommand de crer les interfaces dans un fichier part. Rappelez-vous galement de

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


la convention qui fait que les interfaces doivent commencer par un i majuscule.

193/381

Nous dfinissons ici une interface IVolant qui possde une proprit de type int et une mthode Voler() qui ne renvoie rien. V oil, cest tout simple. Nous avons cr une interface. Les objets qui choisiront dimplmenter cette interface seront obligs davoir une proprit entire NombrePropulseurs et une mthode Voler() qui ne renvoie rien. Rappelez-vous que l'interface ne contient que le contrat et aucune implmentation. C'est--dire que nous ne verrons jamais de corps de mthode dans une interface ni de variables membres ; uniquement des mthodes et des proprits. Un contrat. Notez quand mme quil ne faut pas dfinir de visibilit sur les membres dune interface. Nous serons obligs de dfinir les visibilits en public sur les objets implmentant linterface. Crons dsormais deux objets Avion et Oiseau qui implmentent cette interface, ce qui donne : Code : C# public class Oiseau : IVolant { public int NombrePropulseurs { get; set; } public void Voler() { Console.WriteLine("Je vole grce " + NombrePropulseurs + " ailes"); } } public class Avion : IVolant { public int NombrePropulseurs { get; set; } public void Voler() { Console.WriteLine("Je vole grce " + NombrePropulseurs + " moteurs"); } }

Grce ce contrat, nous savons maintenant que nimporte lequel de ces objets saura voler. Il est possible de traiter ces objets comme des objets volants, un peu comme ce que nous avions fait avec les classes mres, en utilisant linterface comme type pour la variable. Par exemple : Code : C# IVolant oiseau = new Oiseau { NombrePropulseurs = 2 }; oiseau.Voler();

Nous instancions vraiment un objet Oiseau, mais nous le manipulons en tant que IVolant. Un des intrts dans ce cas sera de pouvoir manipuler des objets qui partagent un comportement de la mme faon : Code : C# Oiseau oiseau = new Oiseau { NombrePropulseurs = 2 }; Avion avion = new Avion { NombrePropulseurs = 4 }; List<IVolant> volants = new List<IVolant> { oiseau, avion }; foreach (IVolant volant in volants)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } volant.Voler();

194/381

Ce qui produira :

Grce linterface, nous avons pu mettre dans une mme liste des objets diffrents, qui nhritent pas entre eux mais qui partagent une mme interface, c'est--dire un mme comportement : IVolant. Pour accder ces objets, nous devrons utiliser leurs interfaces. Il sera possible quand mme de caster nos IVolant en Avion ou en Oiseau, si jamais nous souhaitons rajouter une proprit propre lavion. Par exemple je rajoute une proprit NomDuCommandant mon avion mais qui ne fait pas partie de linterface : Code : C# public class Avion : IVolant { public int NombrePropulseurs { get; set; } public string NomDuCommandant { get; set; } public void Voler() { Console.WriteLine("Je vole grce " + NombrePropulseurs + " moteurs"); } }

Cela veut dire que lobjet Avion pourra affecter un nom de commandant mais quil ne sera pas possible dy accder par linterface : Code : C# IVolant avion = new Avion { NombrePropulseurs = 4, NomDuCommandant = "Nico" }; Console.WriteLine(avion.NomDuCommandant); // erreur de compilation

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

195/381

Lerreur de compilation nous indique que IVolant ne possde pas de dfinition pour NomDuCommandant. Ce qui est vrai ! Pour accder au nom du commandant, nous pourrons tenter de caster nos IVolant en Avion. Si le cast est valide, alors nous pourrons accder notre proprit : Code : C# Oiseau oiseau = new Oiseau { NombrePropulseurs = 2 }; Avion avion = new Avion { NombrePropulseurs = 4, NomDuCommandant = "Nico" }; List<IVolant> volants = new List<IVolant> { oiseau, avion }; foreach (IVolant volant in volants) { volant.Voler(); Avion a = volant as Avion; if (a != null) { Console.WriteLine(a.NomDuCommandant); } }

V oil, cest tout simple et a ressemble un peu ce quon a dj vu. Note : lorsque nous avons abord la boucle foreach, jai dit quelle nous servait parcourir des lments numrables . En disant a, je disais en fait que la boucle foreach fonctionne avec tous les types qui implmentent linterface IEnumerable. Maintenant que vous savez ce quest une interface, vous comprenez mieux ce quoi je faisais vraiment rfrence.

Il faut galement noter que les interfaces peuvent hriter entre elles, comme c'est le cas avec les objets. C'est--dire que je vais pouvoir dclarer une interface IVolantMotorise qui hrite de l'interface IVolant. Code : C# public interface IVolant { int NombrePropulseurs { get; set; } void Voler(); } public interface IVolantMotorise : IVolant { void DemarrerLeMoteur(); }

Ainsi, ma classe Avion qui implmentera IVolantMotorise devra obligatoirement implmenter les mthodes/proprits de IVolant ainsi que la mthode de IVolantMotorise : Code : C# public class Avion : IVolantMotorise { public void DemarrerLeMoteur() { } public int NombrePropulseurs { get; set;}

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public void Voler() { }

196/381

Enfin, et nous nous arrterons l pour les interfaces, il est possible pour une classe d'implmenter plusieurs interfaces. Il suffira pour cela de sparer les interfaces par une virgule et d'implmenter bien sr tout ce qu'il faut derrire. Par exemple : Code : C# public interface IVolant { void Voler(); } public interface IRoulant { void Rouler(); } public class Avion : IVolant, IRoulant { public void Voler() { Console.WriteLine("Je vole"); } public void Rouler() { Console.WriteLine("Je Roule"); }

Les classes et les mthodes abstraites


Une classe abstraite est une classe particulire qui ne peut pas tre instancie. Concrtement, cela veut dire que nous ne pourrons pas utiliser loprateur new. De la mme faon, une mthode abstraite est une mthode qui ne contient pas dimplmentation, cest--dire pas de code. Pour tre utilisables, les classes abstraites doivent tre hrites et les mthodes redfinies. En gnral, les classes abstraites sont utilises comme classe de base pour dautres classes. Ces classes fournissent des comportements mais nont pas vraiment dutilit avoir une vie propre. Ainsi, les classes filles qui en hritent pourront bnficier de leurs comportements et devront ventuellement en remplacer dautres. Cest comme une classe incomplte qui ne demande qu tre complte. Si une classe possde une mthode abstraite, alors la classe doit absolument tre abstraite. Linverse nest pas vrai, une classe abstraite peut possder des mthodes non abstraites. V ous aurez rarement besoin dutiliser les classes abstraites en tant que dbutant mais elles pourront vous servir pour combiner la puissance des interfaces lhritage. Bon, voil pour la thorie, passons un peu la pratique. Rappelez-vous nos chiens et nos chats qui drivent dune classe mre Animal. Nous savons quun Animal est capable de se dplacer. Cest un comportement quont en commun tous les animaux. Il est tout fait logique de dfinir une mthode SeDeplacer() au niveau de la classe Animal. Sauf quun chien ne se dplace pas forcment comme un dauphin. Lun a des pattes, lautre des nageoires. Et mme si le chien et le chat semblent avoir un dplacement relativement proche, ils ont chacun des subtilits. Le chat a un mouvement plus gracieux, plus flin. Bref, on se rend compte que nous sommes obligs de redfinir la mthode SeDeplacer() dans chaque classe fille de la classe Animal. Et puis de toute faon, sommes-nous vraiment capables de dire comment se dplace un animal dans labsolu ? La mthode SeDeplacer est une candidate parfaite pour tre une mthode abstraite. Rappelez-vous, la mthode abstraite ne

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

197/381

possde pas dimplmentation et chaque classe fille de la classe possdant cette mthode abstraite devra la spcialiser. Cest exactement ce quil nous faut. Pour dclarer une mthode comme tant abstraite, il faut utiliser le mot-cl abstract et ne fournir aucune implmentation de la mthode, c'est--dire que la dclaration de la mthode doit se terminer par un point-virgule : Code : C# public class Animal { public abstract void SeDeplacer(); }

Si nous tentons de compiler cette classe, nous aurons lerreur suivante : Code : Console

'MaPremiereApplication.Animal.SeDeplacer()' est abstrait, mais est contenu dans la classe

Ah oui cest vrai, on a dit quune classe qui contient au moins une mthode abstraite tait forcment abstraite. Cest le mme principe que pour la mthode, il suffit dutiliser le mot-cl abstract devant le mot-cl class : Code : C# public abstract class Animal { public abstract void SeDeplacer(); }

V oil, notre classe peut compiler tranquillement. Nous avons galement dit quune classe abstraite pouvait contenir des mthodes concrtes et que ctait dailleurs une des grandes forces de ce genre de classes. En effet, il est tout fait pertinent que des animaux puissent mourir. Et l, a se passe pour tout le monde de la mme faon, le cur arrte de battre et on ne peut plus rien faire. Cest triste, mais cest ainsi. Cela veut dire que nous pouvons crer une mthode Mourir() dans notre classe abstraite qui possde une implmentation. Cela donne : Code : C# public abstract class Animal { private Coeur coeur; public Animal() { coeur = new Coeur(); } public abstract void SeDeplacer(); public void Mourir() { coeur.Stop(); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

198/381

Avec une classe Cur qui ne fait pas grand-chose : Code : C# public class Coeur { public void Battre() { Console.WriteLine("Boom boom"); } public void Stop() { Console.WriteLine("Mon coeur s'arrte de battre"); }

Comme prvu, il nest pas possible dinstancier un objet Animal. Si nous tentons lopration : Code : C# Animal animal = new Animal();

nous aurons lerreur de compilation suivante : Code : Console

Impossible de crer une instance de la classe abstraite ou de l'interface 'MaPremiereAppl

Par contre, il est possible de crer une classe Chien qui drive de la classe Animal : Code : C# public class Chien : Animal { }

Cette classe ne pourra pas compiler dans cet tat car il faut obligatoirement redfinir la mthode abstraite SeDeplacer(). Cela se fait en utilisant le mot-cl override, comme on la dj vu. V ous aurez srement remarqu que la mthode abstraite nutilise pas le mot-cl virtual comme cela doit absolument tre le cas lors de la substitution dune mthode dans une classe non-abstraite. Il est ici implicite et ne doit pas tre utilis, sinon nous aurons une erreur de compilation. Et puis cela nous arrange, un seul mot-cl, cest largement suffisant ! Nous devons donc spcialiser la mthode SeDeplacer, soit en crivant la mthode la main, soit en utilisant encore une fois notre ami Visual C# Express. Il suffit de faire un clic droit sur la classe dont hrite Chien (en loccurrence Animal) et de cliquer sur Implmenter une classe abstraite :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

199/381

Visual C# Express nous gnre donc la signature de la mthode substituer : Code : C# public class Chien : Animal { public override void SeDeplacer() { throw new NotImplementedException(); } }

Il ne reste plus qu crire le corps de la mthode SeDeplacer, par exemple : Code : C# public class Chien : Animal { public override void SeDeplacer() { Console.WriteLine("Waouf ! Je me dplace avec mes 4 pattes"); } }

Ainsi, nous pourrons crer un objet Chien et le faire se dplacer puis le faire mourir car il hrite des comportements de la classe Animal. Paix son me. Code : C# Chien max = new Chien(); max.SeDeplacer(); max.Mourir();

ce qui donnera :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

200/381

V ous pouvez dsormais vous rendre compte de la ralit de la phrase que jai crite en introduction : [Les classes abstraites] pourront vous servir pour combiner la puissance des interfaces lhritage . En effet, la classe abstraite peut fournir des implmentations alors que linterface ne propose quun contrat. Cependant, une classe concrte ne peut hriter que dune seule classe mais peut implmenter plusieurs interfaces. La classe abstraite est un peu mi-chemin entre lhritage et linterface.

Les classes partielles


Les classes partielles offrent la possibilit de dfinir une classe en plusieurs fois. En gnral, ceci est utilis pour dfinir une classe sur plusieurs fichiers, si par exemple la classe devient trs longue. Il pourra ventuellement tre judicieux de dcouper la classe en plusieurs fichiers pour regrouper des fonctionnalits qui se ressemblent. On utilise pour cela le mot-cl partial. Par exemple, si nous avons un fichier qui contient la classe Voiture suivante : Code : C# public partial class Voiture { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } }

Nous pourrons complter sa dfinition dans un autre fichier pour lui rajouter par exemple des mthodes : Code : C# public partial class Voiture { public string Rouler() { return "Je roule " + Vitesse + " km/h"; } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

201/381

la compilation, Visual C# Express runit les deux classes en une seule et lobjet fonctionne comme toute autre classe qui ne serait pas forcment partielle. noter quil faut imprativement que les deux classes possdent le mot-cl partial pour que cela soit possible, sinon Visual C# Express gnrera une erreur de compilation : Code : Console Modificateur partiel manquant sur la dclaration de type 'MaPremiereApplication.Voiture'

V ous allez me dire que ce nest pas super utile comme fonctionnalit. Et je vous dirais que vous avez raison. Sauf dans un cas particulier. Les classes partielles prennent de lintrt quand une partie du code de la classe est gnr par Visual C# Express. Cest le cas pour la plupart des plateformes qui servent dvelopper des vraies applications. Par exemple ASP.NET pour un site internet, WPF pour une application Windows, Silverlight pour un client riche, etc. Cest aussi le cas lorsque nous gnrons de quoi permettre daccder une base de donnes. Dans ce cas-l, disons pour simplifier que Visual C# Express va nous gnrer tout un tas dinstructions pour nous connecter la base de donnes ou pour rcuprer des donnes. Toutes ces instructions seront mises dans une classe partielle que nous pourrons enrichir avec nos besoins. Lintrt est que si nous re-gnrons une nouvelle version de notre classe, seul le fichier gnr sera impact. Si nous avions modifi le fichier pour enrichir la classe avec nos besoins, nous aurions perdu tout notre travail. Vu que grce aux classes partielles, ce code est situ dans un autre fichier, il nest donc pas perdu. Pour notre plus grand bonheur ! noter que le mot-cl partial peut se combiner sans problmes avec dautres mots-cls, comme abstract par exemple que nous venons de voir. Il est frquent aussi de voir des classes partielles utilises quand plusieurs dveloppeurs travaillent sur la mme classe. Le fait de sparer la classe en deux fichiers permet de travailler sans se marcher dessus. Nous aurons loccasion de voir des classes partielles gnrs plus tard dans le tutoriel.

Classes statiques et mthodes statiques


Nous avons dj vu le mot-cl static en premire partie de ce tutoriel. Il nous a bien encombrs. Nous nous le sommes trimball pendant un moment, puis il a disparu ! Il est temps de revenir sur ce mot-cl afin de comprendre exactement de quoi il sagit, maintenant que nous avons plus de notions et que nous connaissons les objets et les classes. Jusqu prsent, nous avons utilis le mot-cl static uniquement sur les mthodes et jai vaguement expliqu quil servait indiquer que la mthode est toujours disponible et prte tre utilise. Pas trs convaincant, comme explication mais comme vous tes polis, vous ne maviez rien dit. En fait, le mot-cl static permet dindiquer que la mthode dune classe nappartient pas une instance de la classe. Nous avons vu que jusqu prsent, nous devions instancier nos classes avec le mot-cl new pour avoir des objets. Ici, static permet de ne pas instancier lobjet mais davoir accs cette mthode en dehors de tout objet. Nous avons dj utilis beaucoup de mthodes statiques, je ne sais pas si vous avez fait attention, mais maintenant que vous connaissez les objets, la mthode suivante ne vous parat pas bizarre ? Code : C# Console.WriteLine("Bonjour");

Nous utilisons la mthode WriteLine de la classe Console sans avoir cr dobjet Console. trange. Il sagit, vous laurez devin, dune mthode statique qui est accessible en dehors de toute instance de Console. Dailleurs, la classe entire est une classe statique. Si nous essayons dinstancier la classe Console avec :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# Console c = new Console();

202/381

Nous aurons les messages derreurs suivant : Code : Console Impossible de dclarer une variable de type static 'System.Console' Impossible de crer une instance de la classe static 'System.Console'

Nous avons dit que la mthode spciale Main() est obligatoirement statique. Cela permet au CLR, qui va excuter notre application, de ne pas avoir besoin dinstancier la classe Program pour dmarrer notre application. Il a juste appeler la mthode Program.Main() afin de dmarrer notre programme. Comme la mthode Main() est utilisable en dehors de toute instance de classe, elle ne peut appeler que des mthodes statiques. En effet, comment pourrait-elle appeler des mthodes dun objet alors quelle nen a mme pas conscience ? Cest pour cela que nous avons t obligs de prfixer chacune de nos premires mthodes par le mot-cl static. Revenons nos objets. Ils peuvent contenir des mthodes statiques ou des variables statiques. Si une classe ne contient que des choses statiques alors elle peut devenir galement statique. Une mthode statique est donc une mthode qui ne travaille pas avec les membres (variables ou autres) non statiques de sa propre classe. Rappelez-vous un peu plus haut, nous avions cr une classe Math qui servait faire des additions, afin dillustrer le polymorphisme : Code : C# public class Math { public int Addition(int a, int b) { return a + b; } }

que nous utilisions de cette faon : Code : C# Math math = new Math(); int resultat = math.Addition(5, 6);

Ici, la mthode addition sert additionner 2 entiers. Elle est compltement indpendante de la classe Math et donc des instances de lobjet Math. Nous pouvons donc en faire une mthode statique, pour cela il suffira de prfixer du mot-cl static son type de retour : Code : C# public class Math { public static int Addition(int a, int b)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } } return a + b;

203/381

Et nous pourrons alors utiliser laddition sans crer dinstance de la classe Math, mais simplement en utilisant le nom de la classe suivi du nom de la mthode statique : Code : C# int resultat = Math.Addition(5, 6);

Exactement comme nous avons fait pour Console.WriteLine. De la mme faon, nous pouvons rajouter dautres mthodes, comme la multiplication : Code : C# public class Math { public static int Addition(int a, int b) { return a + b; } public static long Multiplication(int a, int b) { return a * b; }

Que nous appellerons de la mme faon : Code : C# long resultat = Math.Multiplication(5, 6);

noter que la classe Mathest toujours instanciable mais quil nest pas possible dappeler les mthodes qui sont statiques depuis un objet Math. Le code suivant : Code : C# Math math = new Math(); long resultat = math.Multiplication(5, 6);

provoquera lerreur de compilation : Code : Console

Le membre 'MaPremiereApplication.Math.Multiplication(int, int)' est inaccessible avec une le avec un nom de type

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

204/381

Ok, mais quoi a sert de pouvoir instancier un objet Math si nous ne pouvons accder aucune de ses mthodes, vu quelles sont statiques ?

Absolument rien ! Si une classe ne possde que des membres statiques, alors il est possible de rendre cette classe statique grce au mme mot-cl. Celle-ci deviendra non-instanciable, comme la classe Console : Code : C# public static class Math { public static int Addition(int a, int b) { return a + b; } }

Ainsi, si nous tentons dinstancier lobjet Math, nous aurons une erreur de compilation. En gnral, les classes statiques servent regrouper des mthodes utilitaires qui partagent une mme fonctionnalit. Ici, la classe Math permettrait dy ranger toutes les mthodes du style addition, multiplication, racine carre, etc Ah, on me fait signe que cette classe existe dj dans le framework .NET et quelle sappelle galement Math. Elle est range dans lespace de nom System. Souvenez-vous, nous lavons utilise pour calculer la racine carre. Cette classe est statique, cest la version aboutie de la classe que nous avons commenc crire. Par contre, ce nest pas parce quune classe possde des mthodes statiques quelle est obligatoirement statique. Il est aussi possible davoir des membres statiques dans une classe qui possde des membres non statiques. Par exemple notre classe Chien, qui possde un prnom et qui sait aboyer : Code : C# public class Chien { private string prenom; public Chien(string prenomDuChien) { prenom = prenomDuChien; } public void Aboyer() { Console.WriteLine("Wouaf ! Je suis " + prenom); }

pourrait possder une mthode permettant de calculer lge dun chien dans le rfrentiel des humains. Comme beaucoup le savent, il suffit de multiplier lge du chien par 7. Code : C# public class Chien { private string prenom; public Chien(string prenomDuChien) {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} prenom = prenomDuChien;

205/381

public void Aboyer() { Console.WriteLine("Wouaf ! Je suis " + prenom); } public static int CalculerAge(int ageDuChien) { return ageDuChien * 7; }

Ici, la mthode CalculerAge() est statique car elle ne travaille pas directement avec une instance dun chien. Nous pouvons lappeler ainsi : Code : C# Chien hina = new Chien("Hina"); hina.Aboyer(); int ageReferentielHomme = Chien.CalculerAge(4); Console.WriteLine(ageReferentielHomme);

Ce qui donne :

V ous me direz quil est possible de faire en sorte que la mthode travaille sur une instance dun objet Chien, ce qui serait peuttre plus judicieux ici. Il suffirait de rajouter une proprit Age au Chien et de transformer la mthode pour quelle ne soit plus statique. Ce qui donnerait : Code : C# public class Chien { private string prenom;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public int Age { get; set; } public Chien(string prenomDuChien) { prenom = prenomDuChien; } public void Aboyer() { Console.WriteLine("Wouaf ! Je suis " + prenom); } public int CalculerAge() { return Age * 7; }

206/381

Que lon pourrait appeler de cette faon : Code : C# Chien hina = new Chien("Hina") { Age = 5 }; int ageReferentielHomme = hina.CalculerAge(); Console.WriteLine(ageReferentielHomme);

Ici, cest plus une histoire de conception. Cest vous de dcider, mais sachez que cest possible. Il est galement possible dutiliser le mot-cl static avec des proprits. Imaginions que nous souhaitions avoir un compteur sur le nombre dinstances de la classe Chien. Nous pourrions crer une proprit statique de type entier qui sincrmente chaque fois que lon cre un nouveau chien : Code : C# public class Chien { public static int NombreDeChiens { get; set; } private string prenom; public Chien(string prenomDuChien) { prenom = prenomDuChien; NombreDeChiens++; } public void Aboyer() { Console.WriteLine("Wouaf ! Je suis " + prenom); }

Ici, la proprit NombreDeChiens est statique et est incrmente chaque passage dans le constructeur. Ainsi, si nous crons plusieurs chiens : Code : C# Chien chien1 = new Chien("Max"); Chien chien2 = new Chien("Hina"); Chien chien3 = new Chien("Laika");

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Console.WriteLine(Chien.NombreDeChiens);

207/381

Nous pourrons voir combien de fois nous sommes passs dans le constructeur :

Pour une variable statique, cela se passe de la mme faon qu'avec les proprits statiques.

Les classes internes


Les classes internes (nested class en anglais) sont un mcanisme qui permet davoir des classes dfinies lintrieur dautres classes. Cela peut tre utile si vous souhaitez restreindre laccs dune classe uniquement sa classe mre. Par exemple : Code : C# public class Chien { private Coeur coeur = new Coeur(); public void Mourir() { coeur.Stop(); } private class Coeur { public void Stop() { Console.WriteLine("The end"); } }

Ici, la classe Cur ne peut tre utilise que par la classe Chien car elle est prive. Nous pourrions galement mettre la classe en protected afin quune classe drive de la classe Chien puisse galement utiliser la classe Cur : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

208/381

public class ChienSamois : Chien { private Coeur autreCoeur = new Coeur(); }

Avec ces niveaux de visibilit, une autre classe comme la classe Chat ne pourra pas se servir de ce cur. Si nous mettons la classe Cur en public ou internal, elle sera utilisable par tout le monde ; comme une classe normale. Dans ce cas, nos chats pourront avoir : Code : C# public class Chat { private Chien.Coeur coeur = new Chien.Coeur(); public void Mourir() { coeur.Stop(); }

Notez que nous prfixons la classe par le nom de la classe qui contient la classe Cur. Dans ce cas, lintrt dutiliser une classe interne est moindre. Cela permet ventuellement de regrouper les classes de manire smantique, et encore, cest plutt le but des espaces de noms. V pour les classes internes. Cest une fonctionnalit souvent peu utilise, mais voil, vous la connaissez dsormais oil .

Les types anonymes et le mot cl var


Le mot-cl var est un truc de feignant ! Il permet de demander au compilateur de dduire le type dune variable au moment o nous la dclarons. Par exemple le code suivant : Code : C# var prenom = "Nicolas"; var age = 30;

est quivalent au code suivant : Code : C# string prenom = "Nicolas"; int age = 30;

Le mot-cl var sert indiquer que nous ne voulons pas nous proccuper de ce quest le type et que cest au compilateur de le trouver. Cela implique quil faut que la variable soit initialise (et non nulle) au moment o elle est dclare afin que le compilateur puisse dduire le type de la variable, en loccurrence, il devine quen lui affectant Nicolas , il sagit dune chane de caractres. Je ne recommande pas lutilisation de ce mot-cl, car le fait de ne pas mettre le type de la variable fait perdre de la clart au code. Ici, cest facile. On dduit facilement nous aussi que le type de prenom est string et que le type de age est int. Mais cest aussi parce quon est trop fort !

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Par contre, si jamais la variable est initialise grce une mthode : Code : C# var calcul = GetCalcul();

209/381

il va falloir aller regarder la dfinition de la mthode afin de savoir le type de retour et connaitre ainsi le type de la variable. Des contraintes dont on na pas besoin alors quil est aussi simple dindiquer le vrai type et que cest dautant plus lisible. Mais alors, pourquoi en parler ?

Parce que ce mot-cl peut servir dans un cas prcis, celui des types anonymes. Lorsquil est conjointement utilis avec loprateur new, il permet de crer des types anonymes, c'est--dire des types dont on na pas dfini la classe au pralable. Une classe sans nom. Cette classe est dduite grce son initialisation : Code : C# var unePersonneAnonyme = new { Prenom = "Nico", Age = 30 };

Ici nous crons une variable qui contient une proprit Prenom et une proprit Age. Forcment, il est impossible de donner un type cette variable vu quelle na pas de dfinition. Cest pour cela quon utilise le mot-cl var. On sait juste que la variable unePersonneAnonyme possde deux proprits, un prnom et un ge. En interne, le compilateur va gnrer un nom de classe pour ce type anonyme, mais il na pas de sens pour nous. En loccurrence, si nous crivons le code suivant o GetType() (hrit de la classe object) renvoie le nom du type : Code : C# var unePersonneAnonyme = new { Prenom = "Nico", Age = 30 }; Console.WriteLine(unePersonneAnonyme.GetType());

nous aurons :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

210/381

Ce qui est effectivement sans intrt pour nous ! Jusquici, les types anonymes peuvent sembler ne pas apporter dintrt, tant il est simple de dfinir une classe Personne possdant une proprit Prenom et une proprit Age. Mais cela permet dutiliser ces classes comme des classes usage unique lorsque nous ne souhaitons pas nous encombrer dun fichier possdant une classe qui va nous servir uniquement un seul endroit. Paresse, souci de clart du code, tout ceci est un peu ml dans la cration dun type anonyme. vous de lutiliser quand bon vous semble. V ous verrez plus tard que les types anonymes sont souvent utiliss dans les mthodes dextensions Linq. Nous en reparlerons. noter que lorsque nous crons un tableau, par exemple : Code : C# string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };

il est galement possible de l'crire ainsi : Code : C# string[] jours = new[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };

c'est--dire sans prciser le type du tableau aprs le new. Le compilateur dduit le type partir de l'initialisation. Ce n'est pas un type anonyme en soit, mais le principe de dduction est le mme.

En rsum
Une interface est un contrat que s'engage respecter un objet. Il est possible d'implmenter plusieurs interfaces dans une classe. Une classe abstraite est une classe qui possde au moins une mthode ou proprit abstraite. Elle ne peut pas tre instancie.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

211/381

Une classe concrte drivant d'une classe abstraite est oblige de substituer les membres abstraits. Il est possible de crer des types anonymes grce l'oprateur new suivi de la description des proprits de ce type. Les instances sont manipules grce au mot-cl var.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

212/381

TP Programmation Oriente Objet


Dans ce TP, nous allons essayer de mettre en pratique ce que nous avons appris en programmation oriente objet avec le C#. Difficile davoir un exercice qui ncessite toutes les notions que nous avons apprises. Aussi, certaines sont laisses de ct. Avec ce TP, vous aurez l'occasion de vous entraner crer des classes, manipuler lhritage et vous pourrez vous confronter des situations un peu diffrentes de la thorie ! Le but du TP est de crer une mini application de gestion bancaire o nous pourrons grer des comptes qui peuvent faire des oprations bancaires entre eux. Ne vous attendez pas non plus refaire les applications de la banque de France, on est l pour s'entrainer. Ce TP sera dcompos en deux parties.

Instructions pour raliser le TP


Alors voici l'nonc de la premire partie du TP. Dans notre mini application bancaire tous les montants utiliss seront des dcimaux. Nous allons devoir grer des comptes bancaires. Un compte est compos : Dun Solde (calcul, mais non modifiable) ; Dun Propritaire (nom du propritaire du compte) ; Dune liste doprations interne permettant de garder lhistorique du compte, non accessible par les autres objets ; Dune mthode permettant de Crediter() le compte, prenant une somme en paramtre ; Dune mthode permettant de Crediter() le compte, prenant une somme et un compte en paramtres, crditant le compte et dbitant le compte pass en paramtres ; Dune mthode permettant de Debiter() le compte, prenant une somme en paramtre ; Dune mthode permettant de Dbiter() le compte, prenant une somme et un compte bancaire en paramtres, dbitant le compte et crditant le compte pass en paramtres ; Dune mthode qui permet dafficher le rsum dun compte.

Un compte courant est une sorte de compte et est compos : De tout ce qui compose un compte ; Dun dcouvert autoris, non modifiable, dfini louverture du compte ; Le rsum dun compte courant affiche le solde, le propritaire, le dcouvert autoris ainsi que les oprations sur le compte.

Un compte pargne entreprise est une sorte de compte et est compos : De tout ce qui compose un compte ; Dun taux dabondement, dfini louverture du compte en fonction de lanciennet du salari. Un taux est un double compris entre 0 et 1. (5% = 0.05) ; Le solde doit tenir compte du taux dabondement, mais labondement nest pas calcul lors des transactions car lentreprise verse labondement quand elle le souhaite ; le rsum dun compte pargne entreprise affiche le solde, le propritaire, le taux dabondement ainsi que les oprations sur le compte.

Une opration bancaire est compose : Dun montant ; Dun type de mouvement, crdit ou dbit.

Crer une telle application avec les informations suivantes :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Le compte courant de Nicolas a un dcouvert autoris de 2000 Le compte pargne entreprise de Nicolas a un taux de 2% Le compte courant de Jrmie a un dcouvert autoris de 500 Nicolas touche son salaire de 100, pas cher pay ! Il fait le plein de sa voiture : 50 Il met de ct sur son compte pargne entreprise la coquette somme de 20 Puis il reoit un cadeau de la banque de 100 car il a ouvert son compte pendant la priode promotionnelle Il remet ses 20 sur son compte bancaire car finalement, il ne se sent pas mga en scurit Jrmie achte un nouveau PC : 500 Puis il rembourse ses dettes Nicolas : 200

213/381

Lapplication doit indiquer les soldes de chacun de ces comptes : Code : Console Solde compte courant de Nicolas : 250 Solde compte pargne de Nicolas : 102,00 Solde compte courant de Jrmie : -700

Ensuite, nous afficherons le rsum du compte courant de Nicolas et de son compte pargne entreprise. Ce qui nous donnera : Code : Console Rsum du compte de Nicolas ******************************************* Compte courant de Nicolas Solde : 250 Dcouvert autoris : 2000 Oprations : +100 -50 -20 +20 +200 ******************************************* Rsum du compte pargne de Nicolas ######################################################## Compte pargne entreprise de Nicolas Solde : 102,00 Taux : 0,02 Oprations : +20 +100 -20 ########################################################

Bon, jai bien expliqu, ce nest pas si compliqu, sauf si bien sr vous navez pas lu ou pas compris les chapitres prcdents. Dans ce cas, nhsitez pas y rejeter un coup dil. Sinon, il suffit de bien dcomposer tout en crant les classes les unes aprs les autres. Bon courage !

Correction
Ne regardez pas tout de suite la correction. Faites le TP. Il est important de manipuler les classes. V ous allez faire a trs

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


rgulirement. Cela doit devenir un rflexe et pour que cela le devienne, il faut pratiquer ! Toujours est-il que voici ma correction. Peut-tre que le plus dur est de modliser correctement lapplication ? Il y a plusieurs solutions bien sr pour crer ce petit programme, voici celle que je propose.

214/381

Tout dabord, nous devons manipuler des comptes courant et des comptes pargne entreprise, qui sont des sortes de comptes. On en dduit quun compte courant hrite dun compte. De mme, un compte pargne entreprise hrite galement dun compte. Dailleurs, un compte a-t-il vraiment une raison dtre part entire ? Nous ne crons jamais de compte gnraliste , seulement des comptes spcialiss. Nous allons donc crer la classe compte en tant que classe abstraite. Ce qui nous donnera les classes suivantes : Code : C# public abstract class Compte { } public class CompteCourant : Compte { } public class CompteEpargneEntreprise : Compte { }

Nous avons galement dit quun compte tait compos dune liste doprations qui possdent un montant et un type de mouvement. Le type de mouvement pouvant prendre 2 valeurs, il parait logique dutiliser une numration : Code : C# public enum Mouvement { Credit, Debit }

La classe dopration tant : Code : C# public class Operation { public Mouvement TypeDeMouvement { get; set; } public decimal Montant { get; set; } }

V pour la base. oil Ensuite, la classe Compte doit possder un nom de propritaire et un solde qui peut tre redfini dans la classe CompteEpargneEntreprise. Ce solde est calcul partir dune liste doprations. Le solde est donc une proprit en lecture seule, virtuelle car ncessitant dtre redfinie : Code : C# public abstract class Compte

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ protected List<Operation> listeOperations; public string Proprietaire { get; set; } public virtual decimal Solde { get { decimal total = 0; foreach (Operation operation in listeOperations) { if (operation.TypeDeMouvement == Mouvement.Credit) total += operation.Montant; else total -= operation.Montant; } return total; } }

215/381

La liste des oprations est une variable membre, dclare en protected car nous allons en avoir besoin dans la classe CompteCourant qui en hrite, afin dafficher un rsum des oprations. La proprit Solde nest pas trs complique en soit, il suffit de parcourir la liste des oprations et en fonction du type de mouvement, ajouter ou retrancher le montant. Comme cest une proprit en lecture seule, seul le get est dfini. Noubliez pas que la liste doit tre initialise avant dtre utilise, sinon nous aurons une erreur. Le constructeur est un endroit appropri pour le faire : Code : C# public { // // // abstract class Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

public Compte() { listeOperations = new List<Operation>(); }

La classe doit ensuite possder des mthodes permettant de crditer ou de dbiter le compte, ce qui donne : Code : C# public { // // // abstract class Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

public void Crediter(decimal montant) { Operation operation = new Operation { Montant = montant, TypeDeMouvement = Mouvement.Credit}; listeOperations.Add(operation); } public void Crediter(decimal montant, Compte compte)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } Crediter(montant); compte.Debiter(montant);

216/381

public void Debiter(decimal montant) { Operation operation = new Operation { Montant = montant, TypeDeMouvement = Mouvement.Debit }; listeOperations.Add(operation); } public void Debiter(decimal montant, Compte compte) { Debiter(montant); compte.Crediter(montant); }

Le principe est de crer une opration et de lajouter la liste des oprations. Lastuce ici consiste rutiliser les mthodes de la classe pour crire les autres formes des mthodes, ce qui simplifie le travail et facilitera les ventuelles futures oprations de maintenance. Enfin, chaque classe drive de la classe Compte doit afficher un rsum du compte. Nous pouvons donc forcer ces classes devoir implmenter cette mthode en utilisant une mthode abstraite : Code : C# public { // // // } abstract class Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

public abstract void AfficherResume();

V pour la classe Compte. En toute logique, cest elle qui contient le plus de mthodes afin de factoriser le maximum de code oil commun dans la classe mre. Passons la classe CompteEpargneEntreprise, qui hrite de la classe Compte. Elle possde un taux dabondement qui est dfini la cration du compte. Il est donc ici intressant de forcer le positionnement de ce taux lors de la cration de la classe, c'est--dire en utilisant un constructeur avec un paramtre : Code : C# public class CompteEpargneEntreprise : Compte { private double tauxAbondement; public CompteEpargneEntreprise(double taux) { tauxAbondement = taux; }

Ce taux est utilis pour calculer le solde du compte en faisant la somme de toutes les oprations et en appliquant le taux. Ce qui revient appeler le calcul du solde de la classe mre et lui appliquer le taux. Nous substituons donc la proprit Solde et utilisons le calcul fait dans la classe Compte:

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# public { // // // class CompteEpargneEntreprise : Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

217/381

public override decimal Solde { get { return base.Solde * (decimal)(1 + } }

tauxAbondement);

Rien de plus simple, en utilisant le mot-cl base pour appeler le solde de la classe mre. V ous noterez galement que nous avons eu besoin de caster le taux qui est un double afin de pouvoir le multiplier un dcimal. Enfin, cette classe se doit de fournir une implmentation de la mthode AfficherResume() : Code : C# public { // // // class CompteEpargneEntreprise : Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

public override void AfficherResume() { Console.WriteLine("########################################################"); Console.WriteLine("Compte pargne entreprise de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tTaux : " + tauxAbondement); Console.WriteLine("\n\nOprations :"); foreach (Operation operation in listeOperations) { if (operation.TypeDeMouvement == Mouvement.Credit) Console.Write("\t+"); else Console.Write("\t-"); Console.WriteLine(operation.Montant); } Console.WriteLine("########################################################"); } }

Il sagit dune banale mthode daffichage o nous parcourons la liste contenant les oprations et affichons le montant en fonction du type de mouvement. V pour la classe CompteEpargneEntreprise. oil Il ne reste plus que la classe CompteCourant qui doit galement driver de Compte : Code : C# public class CompteCourant : Compte {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


}

218/381

Un compte courant doit possder un dcouvert autoris, dfini la cration du compte courant. Nous utilisons comme avant un constructeur avec un paramtre : Code : C# public class CompteCourant : Compte { private decimal decouvertAutorise; public CompteCourant(decimal decouvert) { decouvertAutorise = decouvert; }

Il ne restera plus qu fournir une implmentation de la mthode daffichage du rsum : Code : C# public { // // // class CompteCourant : Compte [...] [Code prcdent enlev pour plus de lisibilit] [...]

public override void AfficherResume() { Console.WriteLine("*******************************************"); Console.WriteLine("Compte courant de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tDcouvert autoris : " + decouvertAutorise); Console.WriteLine("\n\nOprations :"); foreach (Operation operation in listeOperations) { if (operation.TypeDeMouvement == Mouvement.Credit) Console.Write("\t+"); else Console.Write("\t-"); Console.WriteLine(operation.Montant); } Console.WriteLine("*******************************************"); } }

V pour nos objets. Cela en fait un petit paquet. Mais ce nest pas fini, il faut maintenant crer des comptes et faire des oil oprations. Lnonc consiste faire les instanciations suivantes, depuis notre mthode Main() : Code : C# CompteCourant compteNicolas = new CompteCourant(2000) { Proprietaire = "Nicolas" }; CompteEpargneEntreprise compteEpargneNicolas = new

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


CompteEpargneEntreprise(0.02) { Proprietaire = "Nicolas" }; CompteCourant compteJeremie = new CompteCourant(500) { Proprietaire = "Jrmie" }; compteNicolas.Crediter(100); compteNicolas.Debiter(50); compteEpargneNicolas.Crediter(20, compteNicolas); compteEpargneNicolas.Crediter(100); compteEpargneNicolas.Debiter(20, compteNicolas); compteJeremie.Debiter(500); compteJeremie.Debiter(200, compteNicolas); Console.WriteLine("Solde compte courant de " + compteNicolas.Proprietaire + " : " + compteNicolas.Solde); Console.WriteLine("Solde compte pargne de " + compteEpargneNicolas.Proprietaire + " : " + compteEpargneNicolas.Solde); Console.WriteLine("Solde compte courant de " + compteJeremie.Proprietaire + " : " + compteJeremie.Solde); Console.WriteLine("\n");

219/381

Rien dextraordinaire. Il ne reste plus qu afficher le rsum des deux comptes demands : Code : C# Console.WriteLine("Rsum du compte de Nicolas"); compteNicolas.AfficherResume(); Console.WriteLine("\n"); Console.WriteLine("Rsum du compte pargne de Nicolas"); compteEpargneNicolas.AfficherResume(); Console.WriteLine("\n");

Nous en avons fini avec la premire partie du TP ! Si vous avez bien compris comment construire des classes, comment les faire hriter entre elles et les interfaces, ce TP na pas d vous poser trop de problmes.

Aller plus loin


Il y a plusieurs choses que je naime pas dans ce code. La premire est la rptition. Dans les deux mthodes AfficherResume() des classes CompteCourant et CompteEpargneEntreprise on affiche les oprations de la mme faon. Si jamais je dois modifier ce code (bug ou volution), je devrais le faire dans les deux classes, au risque den oublier une. Il faut donc factoriser ce code. Il existe pour cela plusieurs solutions simples. La premire est dutiliser une mthode statique pour afficher la liste des oprations. Cette mthode pourrait tre situe dans une classe utilitaire qui prend en paramtre la liste des oprations : Code : C# public static class Helper { public static void AfficheOperations(List<Operation> operations) { Console.WriteLine("\n\nOprations :"); foreach (Operation operation in operations) { if (operation.TypeDeMouvement == Mouvement.Credit) Console.Write("\t+");

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


else } Console.Write("\t-"); Console.WriteLine(operation.Montant);

220/381

Il ne reste plus qu utiliser cette mthode statique depuis nos mthodes AfficherResume(), par exemple pour le compte pargne entreprise : Code : C# public override void AfficherResume() { Console.WriteLine("########################################################"); Console.WriteLine("Compte pargne entreprise de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tTaux : " + tauxAbondement); Helper.AfficheOperations(listeOperations); Console.WriteLine("########################################################"); }

La deuxime solution est de crer la mthode AfficheOperations() dans la classe abstraite Compte, ce qui permet de saffranchir de passer la liste en paramtres vu que la classe Compte la connait dj : Code : C# protected void AfficheOperations() { Console.WriteLine("\n\nOprations :"); foreach (Operation operation in listeOperations) { if (operation.TypeDeMouvement == Mouvement.Credit) Console.Write("\t+"); else Console.Write("\t-"); Console.WriteLine(operation.Montant); } }

La mthode a tout intrt tre dclare en protected, afin quelle puisse servir aux classes filles mais pas lextrieur. Elle sutilisera de cette faon, par exemple dans la classe CompteEpargneEntreprise : Code : C# public override void AfficherResume() { Console.WriteLine("########################################################"); Console.WriteLine("Compte pargne entreprise de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tTaux : " + tauxAbondement); AfficheOperations(); Console.WriteLine("########################################################"); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

221/381

Ds que lon peut factoriser du code, il ne faut pas hsiter. Si nous avons demain besoin de crer un nouveau type de compte, nous serons ravis de pouvoir nous servir de mthodes toutes prtes nous simplifiant le travail. Il pourrait tre intressant galement d'encapsuler l'enregistrement d'une opration dans une mthode. Ce qui permet de moins se rpter (mme si ici, le code est vraiment petit) mais qui permet surtout de sparer la logique d'enregistrement d'une opration afin que cela soit plus facile ultrieurement modifier, maintenir ou complexifier. Par exemple, via une mthode : Code : C# private void EnregistrerOperation(Mouvement typeDeMouvement, decimal montant) { Operation operation = new Operation { Montant = montant, TypeDeMouvement = typeDeMouvement}; listeOperations.Add(operation); }

Cela permet galement de faire en sorte que le type de mouvement soit un paramtre de la mthode.

Deuxime partie du TP
Nous voici maintenant dans la deuxime partie du TP. La banque souhaite proposer un nouveau type de compte, le livret ToutBnef. Dans cette banque, le livret ToutBnf fonctionne comme le compte pargne entreprise. Cest--dire quil accepte un taux en paramtres et applique ce taux au moment de la restitution du solde. La premire ide qui vient lesprit est crer une classe LivretToutBenef qui hrite de CompteEpargneEntreprise. Mais ceci pose un problme si jamais le compte pargne entreprise doit voluer, et cest justement ce que le directeur de la banque vient de me confier. Donc, il vous interdit juste titre dhriter de ses fonctionnalits. Ce que vous allez donc faire ici, cest de considrer que le fait quun compte puisse faire des bnfices soit en fait un comportement qui est fourni au moment o on instancie un compte. Il existe plusieurs comportements dont on doit fournir les implmentations : Le comportement de bnfice taux fixe Le comportement de bnfice alatoire Le comportement o il ny a aucun bnfice

Chaque comportement est une classe qui respecte le contrat suivant : Code : C# public interface ICalculateurDeBenefice { decimal CalculeBenefice(decimal solde); double Taux { get; } }

crivez donc ces trois classes de comportement ainsi que le livret ToutBnf qui possde un taux fixe de 2.75% et qui a t crdit une premire fois de 800 et une seconde fois de 200. Affichez enfin son rsum qui devra tenir compte du taux du calculateur de bnfice. Rcrivez ensuite la classe CompteCourant de manire ce quelle ait un comportement o il ny a pas de bnfice. Enfin, la classe CompteEpargneEntreprise subira une volution pour fonctionner avec un comportement de bnfice alatoire (tir entre 0 et 1). Cest parti.

Correction
www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

222/381

Ici cest un peu plus compliqu. V ous ntes sans doute pas compltement familiers avec les notions dinterfaces, aussi avant de vous livrer la correction, je vais vous donner quelques pistes. Le fait davoir un comportement est finalement trs simple. Il suffit davoir un membre priv dans la classe LivretToutBenef du type de linterface. Ce membre priv sera affect la valeur passe en paramtre du constructeur. Cest--dire : Code : C# public class LivretToutBenef : Compte { private ICalculateurDeBenefice calculateurDeBenefice; public LivretToutBenef(ICalculateurDeBenefice calculateur) { calculateurDeBenefice = calculateur; }

Dsormais, les oprations devront se faire avec cette variable, calculateurDeBenefice. On aura galement besoin dinstancier au pralable le comportement voulu et de le passer en paramtres du constructeur. Retournez donc tenter de raliser ce TP avant de voir la suite de la correction . Cest fait ? Alors voici ma correction. Nous avions donc cette interface impose : Code : C# public interface ICalculateurDeBenefice { decimal CalculeBenefice(decimal solde); double Taux { get; } }

Nous avons besoin dcrire plusieurs classes qui implmentent cette interface. La premire est la classe de bnfice taux fixe : Code : C# public class BeneficeATauxFixe : ICalculateurDeBenefice { private double taux; public BeneficeATauxFixe(double tauxFixe) { taux = tauxFixe; } public decimal CalculeBenefice(decimal solde) { return solde * (decimal)(1 + taux); } public double Taux { get { return taux; } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

223/381

Nous avons dit quelle devait prendre un taux en paramtres, le constructeur est lendroit indiqu pour cela. Ensuite, la mthode de calcul est trs simple, il suffit dappliquer la formule au solde. Enfin, la proprit retourne le taux. La classe suivante est la classe de bnfice alatoire. L, pas besoin de paramtres, il suffit de tirer le nombre alatoire dans le constructeur grce la mthode NextDouble(), ce qui donne : Code : C# public class BeneficeAleatoire : ICalculateurDeBenefice { private double taux; private Random random; public BeneficeAleatoire() { random = new Random(); taux = random.NextDouble(); } public decimal CalculeBenefice(decimal solde) { return solde * (decimal)(1 + taux); } public double Taux { get { return taux; } }

Enfin, il faudra crer la classe avec aucun bnfice : Code : C# public class AucunBenefice : ICalculateurDeBenefice { public decimal CalculeBenefice(decimal solde) { return solde; } public double Taux { get { return 0; } }

Rien de sorcier ! L o cela se complique un peu, cest pour la classe LivretToutBenef. Elle doit bien sr driver de la classe de base Compte et possder un membre priv de type ICalculateurDeBenefice : Code : C# public class LivretToutBenef : Compte { private ICalculateurDeBenefice calculateurDeBenefice;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public LivretToutBenef(ICalculateurDeBenefice calculateur) { calculateurDeBenefice = calculateur; } public override decimal Solde { get { return calculateurDeBenefice.CalculeBenefice(base.Solde); } } public override void AfficherResume() {

224/381

Console.WriteLine("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); Console.WriteLine("Livret ToutBnf de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tTaux : " + calculateurDeBenefice.Taux); AfficheOperations(); Console.WriteLine("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); } }

Dans le constructeur, la variable est initialise avec un objet de type ICalculateurDeBenefice. Ensuite, pour calculer le solde, il suffit dappeler la mthode CalculeBenefice avec le solde de base en paramtres. De mme, pour faire apparatre le taux dans le rsum, on pourra utiliser la proprit Taux de linterface. Il ne reste qu souscrire un Livret ToutBnf en lui passant un objet de bnfice taux fixe en paramtre du constructeur, et de faire les oprations bancaires demandes. Ce qui donne : Code : C# ICalculateurDeBenefice beneficeATauxFixe = new BeneficeATauxFixe(0.275); LivretToutBenef livretToutBenefNicolas = new LivretToutBenef(beneficeATauxFixe); livretToutBenefNicolas.Crediter(800); livretToutBenefNicolas.Crediter(200); Console.WriteLine("Rsum du livret Toutbnef"); livretToutBenefNicolas.AfficherResume(); Console.WriteLine("\n");

Ce qui donne : Code : Console Rsum du livret Toutbnef ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Livret ToutBnf de Solde : 1275,000 Taux : 0,275 Oprations : +800 +200 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

225/381

Maintenant, nous devons adapter la classe CompteEpargneEntreprise pour quelle puisse fonctionner avec un comportement. Cela devient tout simple et se rapproche beaucoup du livret ToutBnf : Code : C# public class CompteEpargneEntreprise : Compte { private ICalculateurDeBenefice calculateurDeBenefice; public CompteEpargneEntreprise(ICalculateurDeBenefice calculateur) { calculateurDeBenefice = calculateur; } public override decimal Solde { get { return calculateurDeBenefice.CalculeBenefice(base.Solde); } } public override void AfficherResume() { Console.WriteLine("########################################################"); Console.WriteLine("Compte pargne entreprise de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tTaux : " + calculateurDeBenefice.Taux); AfficheOperations(); Console.WriteLine("########################################################"); } }

Il faut maintenant changer linstanciation de lobjet CompteEpargneEntreprise en lui passant en paramtres un objet de type bnfice alatoire : Code : C# ICalculateurDeBenefice beneficeAleatoire = new BeneficeAleatoire(); CompteEpargneEntreprise compteEpargneNicolas = new CompteEpargneEntreprise(beneficeAleatoire) { Proprietaire = "Nicolas" };

Reste le compte courant qui suit le mme principe : Code : C# public class CompteCourant : Compte { private decimal decouvertAutorise; private ICalculateurDeBenefice calculateurDeBenefice; public CompteCourant(decimal decouvert, ICalculateurDeBenefice calculateur) { decouvertAutorise = decouvert; calculateurDeBenefice = calculateur;

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} public override decimal Solde { get { return calculateurDeBenefice.CalculeBenefice(base.Solde); } } public override void AfficherResume() { Console.WriteLine("*******************************************"); Console.WriteLine("Compte courant de " + Proprietaire); Console.WriteLine("\tSolde : " + Solde); Console.WriteLine("\tDcouvert autoris : " + decouvertAutorise); Console.WriteLine("\tTaux : " + calculateurDeBenefice.Taux); AfficheOperations(); Console.WriteLine("*******************************************"); } }

226/381

Que lon pourra instancier avec un objet de type aucun bnfice : Code : C# ICalculateurDeBenefice aucunBenefice = new AucunBenefice(); CompteCourant compteNicolas = new CompteCourant(2000, aucunBenefice) { Proprietaire = "Nicolas" };

Et voil. Lavantage ici est davoir spar les responsabilits dans diffrentes classes. Si jamais nous crons un nouveau compte qui est rmunr grce un bnfice taux fixe, il suffira de rutiliser ce comportement et le tour est jou. noter que les trois calculs de la proprit Solde sont identiques, il pourrait tre judicieux de le factoriser dans la classe mre Compte. Ceci implique que la classe mre possde elle-mme le membre protg du type de linterface. V pour ce TP. Jespre que vous aurez russi avec brio toutes les crations de classes et que vous ne vous tes pas mlangs oil dans les mots-cls. V ous verrez que vous aurez trs souvent besoin dcrire des classes dans ce genre afin de crer une application. Cest un lment indispensable du C# quil est primordial de matriser. Nhsitez pas faire des variations sur ce TP ou crer dautres petits programmes simples vous permettant de vous entrainer. V pour ce TP. Jespre que vous aurez russi avec brio toutes les crations de classes et que vous ne vous tes pas mlangs oil dans les mots-cls. V ous verrez que vous aurez trs souvent besoin dcrire des classes de ce genre afin de crer une application. Cest un lment indispensable du C# quil est primordial de matriser. Nhsitez pas faire des variations sur ce TP ou crer dautres petits programmes simples vous permettant de vous entrainer.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

227/381

Mode de passage des paramtres une mthode


Dans les chapitres prcdents, nous avons dcrit comment on pouvait passer des paramtres une mthode. Nous avons galement vu que les types du framework .NET pouvaient tre des types valeur ou des types rfrence. Ceci influence la faon dont sont traits les paramtres d'une mthode. Nous allons ici prciser un peu ce fonctionnement. Dans ce chapitre, je vais illustrer mes propos en utilisant des mthodes statiques crites dans la classe Program, gnre par Visual C# Express. Le but est de simplifier l'criture et de ne pas s'encombrer d'objets inutiles. videmment, tout ce que nous allons voir fonctionne galement de la mme faon avec les mthodes non statiques prsentes dans des objets.

Passage de paramtres par valeur


Tout au dbut du tutoriel, nous avons appel des mthodes en passant des types simples (int, string, etc.). Nous avons vu quil sagissait de types valeur qui possdent directement la valeur dans la variable. Lorsque nous passons des types valeur en paramtre dune mthode, nous utilisons un passage de paramtre par valeur. Dcortiquons lexemple suivant : Code : C# static void Main(string[] args) { int age = 30; Doubler(age); Console.WriteLine(age); } public static void Doubler(int valeur) { valeur = valeur * 2; Console.WriteLine(valeur); }

Nous dclarons dans la mthode Main() une variable age, de type entier, laquelle nous affectons la valeur 30. Nous appelons ensuite la mthode Doubler() en lui passant cette variable en paramtre. Ce quil se passe cest que le compilateur fait une copie de la valeur de la variable age pour la mettre dans la variable valeur de la mthode Doubler(). La variable valeur a une porte gale au corps de la mthode Doubler(). Nous modifions ensuite la valeur de la variable valeur en la multipliant par deux. tant donn que la variable valeur a reu une copie de la variable age, c'est--dire que le compilateur a dupliqu la valeur 30, le fait de modifier la variable valeur ne change en rien la valeur de la variable age. En effet, si nous excutons le code du dessus, nous allons avoir :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

228/381

Nous passons 30 la mthode Doubler() qui calcule le double de la variable valeur. On affiche 60. Lorsquon revient dans la mthode Main(), nous retrouvons la valeur initiale de la variable age. Elle na bien sr pas t modifie car la mthode Doubler() a travaill sur une copie. Rappelez-vous que ceci est possible car les types intgrs sont facilement copiables, car peu volus.

Passage de paramtres en mise jour


Oui mais si je veux modifier la valeur ?

Pour pouvoir modifier la valeur du paramtre pass, il faut indiquer que la variable est en mode mise jour . Cela se fait grce au mot-cl ref que nous pourrons utiliser ainsi : Code : C# static void Main(string[] args) { int age = 30; Doubler(ref age); Console.WriteLine(age); } public static void Doubler(ref int valeur) { valeur = valeur * 2; }

Comme on peut sen douter, ce code affiche 60. Le mot-cl ref sutilise avant la dfinition du paramtre dans la mthode. Cela implique quil soit galement utilis au moment dappeler la mthode. V ous aurez remarqu que le mot-cl utilis est ref et qu'il ressemble beaucoup au mot rfrence . Ce nest videmment pas un hasard. En fait, avec ce mot-cl nous demandons au compilateur de passer en paramtre une rfrence vers la variable age plutt que den faire une copie. Ainsi, la mthode Doubler() rcupre une rfrence et la variable valeur rfrence alors la mme valeur que la variable age. Ceci implique que toute modification de la valeur rfrence provoque un changement sur la variable

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


source puisque les variables rfrencent la mme valeur.

229/381

V pourquoi la variable est modifie aprs le passage dans la mthode Doubler(). oil Bien sr, il aurait tout fait t possible de faire en sorte que la mthode Doubler() renvoie un entier contenant la valeur passe en paramtre multiplie par 2 : Code : C# static void Main(string[] args) { int age = 30; age = Doubler(age); Console.WriteLine(age); } public static int Doubler(int valeur) { return valeur * 2; }

Cest ce que nous avons toujours fait auparavant. V donc une autre faon de faire qui peut tre bien utile quand il y a plus oici dune valeur renvoyer.

Passage des objets par rfrence


Cest aussi comme a que cela fonctionne pour les objets. Nous avons vu que les variables qui stockent des objets possdent en fait la rfrence de lobjet. Le fait de passer un objet une mthode quivaut passer la rfrence de lobjet en paramtres. Ainsi, cest comme si on utilisait le mot-cl ref implicitement. Le code suivant : Code : C# static void Main(string[] args) { Voiture voiture = new Voiture { Couleur = "Grise" }; Repeindre(voiture); Console.WriteLine(voiture.Couleur); } public static void Repeindre(Voiture voiture) { voiture.Couleur = "Bleue"; }

va donc crer un objet Voiture et le passer en paramtres la mthode Repeindre(). Comme Voiture est un type rfrence, il ny a pas de duplication de lobjet et une rfrence est passe la mthode. Lorsque nous modifions la proprit Couleur de la voiture, nous modifions bien le mme objet que celui prsent dans la mthode Main(). Nous aurons donc :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

230/381

Il est noter quand mme que la variable voiture de la mthode Repeindre est une copie de la variable voiture de la mthode Main() qui contiennent toutes les deux une rfrence vers l'objet de type Voiture. Cela veut dire que l'on accde bien au mme objet, d'o le rsultat, mais que les deux variables sont indpendantes. Si nous modifions directement la variable, avec par exemple : Code : C# static void Main(string[] args) { Voiture voiture = new Voiture { Couleur = "Grise" }; Repeindre(voiture); Console.WriteLine(voiture.Couleur); } public static void Repeindre(Voiture voiture) { voiture.Couleur = "Bleue"; voiture = null; }

Alors, ce code continuera fonctionner, car la variable voiture de la mthode Main() ne vaut pas null. Le fait de modifier la variable de la mthode Repeindre, qui est une copie, n'affecte en rien la variable de la mthode Main(). Par contre, elle est affecte si nous utilisons le mot-cl ref. Par exemple le code suivant : Code : C# static void Main(string[] args) { Voiture voiture = new Voiture { Couleur = "Grise" }; Repeindre(ref voiture); Console.WriteLine(voiture.Couleur); } public static void Repeindre(ref Voiture voiture) { voiture.Couleur = "Bleue"; voiture = null; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

231/381

provoquera une erreur. En effet, cette fois-ci, c'est bien la rfrence qui est passe nulle et pas une copie de la variable contenant la rfrence... Une subtile diffrence.

Passage de paramtres en sortie


Enfin, le dernier mode de passage est le passage de paramtres en sortie. Il permet de faire en sorte quune mthode force linitialisation dune variable et que lappelant rcupre la valeur initialise. Nous avons dj vu ce mode de passage quand nous avons tudi les conversions. Souvenez-vous de ce code : Code : C# string chaine = "1234"; int nombre; if (int.TryParse(chaine, out nombre)) Console.WriteLine(nombre); else Console.WriteLine("Conversion impossible");

La mthode TryParse permet de tester la conversion dune chane. Elle renvoie vrai ou faux en fonction du rsultat de la conversion et met jour lentier qui est pass en paramtre en utilisant le mot-cl out . Si la conversion russit, alors lentier nombre est initialis avec la valeur de la conversion, calcule dans la mthode TryParse. Nous pouvons utiliser ensuite la variable nombre car le mot-cl out garantit que la variable sera initialise dans la mthode. En effet, si nous prenons lexemple suivant : Code : C# static void Main(string[] args) { int age = 30; int ageDouble; Doubler(age, out ageDouble); } public static void Doubler(int age, out int resultat) { }

Nous aurons une erreur de compilation : Code : Console

Le paramtre de sortie 'resultat' doit tre assign avant que le contrle quitte la mtho

En effet, il faut absolument que la variable resultat qui est marque en sortie ait une valeur avant de pouvoir sortir de la mthode. Nous pourrons corriger cet exemple avec : Code : C# static void Main(string[] args)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ int age = 30; int ageDouble; Doubler(age, out ageDouble);

232/381

public static void Doubler(int age, out int resultat) { resultat = age * 2; }

Aprs lappel de la mthode Doubler(), ageDouble vaudra donc 60. Oui, mais quel intrt par rapport un return normal ?

Ici, aucun. Cela est pertinent quand nous souhaitons renvoyer plusieurs valeurs, comme cest le cas pour la mthode TryParse qui renvoie le rsultat de la conversion et si la conversion sest bien passe. Bien sr, si lon naime pas trop le mot-cl out, il est toujours possible de crer un objet contenant deux valeurs que lon retournera lappelant, par exemple : Code : C# public class Program { static void Main(string[] args) { string nombre = "1234"; Resultat resultat = TryParse(nombre); if (resultat.ConversionOk) Console.WriteLine(resultat.Valeur); } public static Resultat TryParse(string chaine) { Resultat resultat = new Resultat(); int valeur; resultat.ConversionOk = int.TryParse(chaine, out valeur); resultat.Valeur = valeur; return resultat; } } public class Resultat { public bool ConversionOk { get; set; } public int Valeur { get; set; } }

Ici, notre mthode TryParse renvoie un objet Resultat qui contient les deux valeurs rsultantes de la conversion.

En rsum

Le type d'une variable passe en paramtres d'une mthode influence la faon dont elle est traite. Un passage par valeur effectue une copie de la valeur de la variable et la met dans la variable de la mthode. Un passage par rfrence effectue une copie de la rfrence mais continue de pointer sur le mme objet. On utilise le mot-cl ref pour passer une variable de type valeur une mthode afin de la modifier.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

233/381

Les structures
Nous allons aborder dans ce chapitre les structures qui sont une nouvelle sorte dobjets que nous pouvons crer dans des applications C#. Les structures sont presque comme des classes. Elles permettent galement de crer des objets, possdent des variables ou proprits, des mthodes et mme un constructeur, mais avec quelques subtiles diffrences Dcouvrons les ds prsent.

Une structure est presque une classe


Une des premires diffrences est la faon dont .NET gre ces deux objets. Nous avons vu que les classes taient des types rfrence. Les variables de type rfrence ne possdent donc pas la valeur de lobjet mais une rfrence vers cet objet en mmoire. La structure quant elle est un type valeur et contient donc directement la valeur de lobjet. Une autre diffrence est que la structure, bien qutant un objet, ne peut pas utiliser les principes dhritage. On ne peut donc pas hriter dune structure et une structure ne peut pas hriter des comportements dun objet.

quoi sert une structure ?


Les structures vont tre utiles pour stocker des petits objets qui vont avoir tendance tre souvent manipuls, comme les int ou les bool que nous avons dj vus. La raison tient dans un seul mot : performance. tant gres en mmoire diffremment, les structures sont optimises pour amliorer les performances des petits objets. Comme il ny a pas de rfrence, on utilisera directement lobjet sans aller le chercher via sa rfrence. On gagne donc un peu de temps lorsquon a besoin de manipuler ces donnes. Cest tout fait pertinent pour des programmes o la vitesse est dterminante, comme les jeux vido. Donc dans ce cas, autant utiliser tout le temps des structures, non ?

Eh bien non, dj vous vous priveriez de tous les mcanismes dhritage que nous avons vus. Ensuite, si nous surchargeons trop la mmoire avec des structures, loptimisation prvue par .NET risque de se retourner contre nous et notre application pourrait tre plus lente que si nous avions utilis des classes. Dune manire gnrale, et moins de savoir exactement ce que vous faites ou davoir mesur les performances, vous allez utiliser plus gnralement les classes que les structures. V ous pouvez ce sujet aller lire les recommandations de Microsoft.

Crer une structure


Pour crer une structure, nous utiliserons le mot-cl struct, comme nous avions utilis le mot-cl class pour crer une classe : Code : C# public struct Personne { public string Prenom { get; set; } public int Age { get; set; } }

Pour instancier cette structure, nous pourrons utiliser le mot-cl new, comme pour les classes. La diffrence est que la variable sera un type valeur, avec les consquences que ce type impose en matire de gestion en mmoire ou de passages par paramtres : Code : C# Personne nicolas = new Personne() { Prenom = "Nicolas", Age = 30 }; Console.WriteLine(nicolas.Prenom + " a " + nicolas.Age + " ans");

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

234/381

Comme nous avons dit, il est impossible quune structure hrite dune autre structure ou dun objet. Sauf bien sr du fameux type de base object, pour qui cest automatique. Une structure hrite donc des quelques mthodes dObject (comme ToString()) que nous pouvons ventuellement spcialiser : Code : C# public struct Personne { public string Prenom { get; set; } public int Age { get; set; } public override string ToString() { return Prenom + " a " + Age + " ans"; }

Et nous pourrons avoir : Code : C# Personne nicolas = new Personne() { Prenom = "Nicolas", Age = 30 }; Console.WriteLine(nicolas.ToString());

Qui renverra : Code : Console Nicolas a 30 ans

Comme pour les classes, il est possible davoir des constructeurs sur une structure lexception du constructeur par dfaut qui est interdit. Aussi le code suivant : Code : C# public struct Personne { public Personne() { } }

provoquera lerreur de compilation suivante : Code : Console Les structures ne peuvent pas contenir de constructeurs exempts de paramtres explicites

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Par contre, les autres formes des constructeurs sont possibles, comme : Code : C# public struct Personne { private int age; public Personne(int agePersonne) { age = agePersonne; } }

235/381

Qui sutilisera comme pour une classe : Code : C# Personne nicolas = new Personne(30);

Attention, si vous tentez dutiliser des proprits ou des mthodes dans le constructeur dune structure, vous allez avoir un problme. Par exemple le code suivant : Code : C# public struct Personne { private int age; public Personne(int agePersonne) { AffecteAge(agePersonne); } private void AffecteAge(int agePersonne) { age = agePersonne; }

provoquera les erreurs de compilation suivantes : Code : Console L'objet 'this' ne peut pas tre utilis avant que tous ses champs soient assigns

Le champ 'MaPremiereApplication.Personne.age' doit tre totalement assign avant que le c

Alors quavec une classe, ce code serait tout fait correct. Pour corriger ceci, il faut absolument initialiser tous les champs avant de faire quoi que ce soit avec lobjet, comme lindique lerreur. Nous pourrons par exemple faire :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# public struct Personne { private int age; public Personne(int agePersonne) { age = 0; AffecteAge(agePersonne); } private void AffecteAge(int agePersonne) { age = agePersonne; }

236/381

Ce qui peut sembler tout fait inutile dans ce cas-l. Mais comme le compilateur fait certaines vrifications, il sera impossible de compiler un code de ce genre sans que toutes les variables soient initialises explicitement. Par contre, vous aurez un souci si vous utilisez des proprits automatiques. Si nous tentons de faire : Code : C# public struct Personne { public int Age { get; set; } public Personne(int agePersonne) { Age = agePersonne; } }

nous nous retrouverons avec la mme erreur de compilation. Pour la corriger, il faudra appeler le constructeur par dfaut de la structure qui va permettre dinitialiser toutes les variables de la classe : Code : C# public struct Personne { public int Age { get; set; } public Personne(int agePersonne) : this() { Age = agePersonne; } }

Cela se fait comme pour les classes, en utilisant le mot-cl this suivi de parenthses qui permettront dappeler le constructeur par dfaut. Rappelez-vous que le constructeur par dfaut soccupe dinitialiser toutes les variables dune classe ou dune structure.

Passage de structures en paramtres


Comme il sagit dun type valeur, chaque fois que nous passerons une structure en paramtres dune mthode, une copie de lobjet sera faite. Ainsi, tout fait logiquement, le code suivant : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


static void Main(string[] args) { Personne nicolas = new Personne() { Age = 30 }; FaitVieillir(nicolas); Console.WriteLine(nicolas.Age); } private static void FaitVieillir(Personne personne) { personne.Age++; }

237/381

affichera 30 bien que nous modifions lge de la personne dans la mthode. Comme nous lavons dj vu, la mthode travaille sur une copie de la structure. Cela veut bien sr dire que si nous souhaitons modifier une structure partir dune mthode, nous devrons utiliser le mot-cl ref : Code : C# static void Main(string[] args) { Personne nicolas = new Personne() { Age = 30 }; FaitVieillir(ref nicolas); Console.WriteLine(nicolas.Age); } private static void FaitVieillir(ref Personne personne) { personne.Age++; }

Cela vaut pour tous les types valeur. Prenez quand mme garde. Si la structure est trs grosse, le fait den faire une copie chaque utilisation de mthode risque dtre particulirement chronophage et pourra perturber les performances de votre application.

Dautres structures ?
V ous laurez peut-tre devin, mais les entiers que nous avons dj vus et que nous utilisions grce au mot-cl int sont en fait des structures. tant trs souvent utiliss et nayant pas non plus normment de choses stocker, ils sont crs en tant que structures et sont optimiss par .NET pour que nos applications sexcutent de faon optimale. Ce qui est un choix tout fait pertinent. C'est le cas galement pour les bool, les double/minicode>, etc ... Toutefois, dautres objets, comme la classe <minicode type="csharp">String, sont bel et bien des classes. Dune manire gnrale, vous allez crer peu de structures en tant que dbutant. Il sera plus judicieux de crer des classes ds que vous en avez besoin. En effet, plus vos objets sont gros et plus ils auront intrt tre des classes pour viter dtre recopis chaque utilisation. Lutilisation de structures pourra se rvler pertinente dans des situations bien prcises, mais en gnral, il faut bien maitriser les rouages du framework .NET pour que les bnfices de leurs utilisations se fassent ressentir. Dans tous les cas, il sera important de mesurer (avec par exemple des outils de profilage) le gain de temps avant de mettre des structures partout.

En rsum
Les structures sont des types valeur qui sont optimiss par le framework .NET. Une structure est un objet qui ressemble beaucoup une classe, mais qui possde des restrictions. Les structures possdent des proprits, des mthodes, des constructeurs, etc. Il n'est pas possible d'utiliser l'hritage avec les structures.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

238/381

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

239/381

Les gnriques
Les gnriques sont une fonctionnalit du framework .NET apparus avec la version 2. V ous vous en souvenez peut-tre, nous avons cit le mot dans le chapitre sur les tableaux et les listes. Ils permettent de crer des mthodes ou des classes qui sont indpendantes d'un type. Il est trs important de connatre leur fonctionnement car c'est un mcanisme cl qui permet de faire beaucoup de choses, notamment en termes de rutilisabilit et d'amlioration des performances. N'oubliez pas vos tubes d'aspirine et voyons prsent de quoi il retourne !

Qu'est-ce que les gnriques ?


Avec les gnriques, vous pouvez crer des mthodes ou des classes qui sont indpendantes dun type. On les appellera des mthodes gnriques et des types gnriques. Nous en avons dj utilis, rappelez-vous, avec la liste. La liste est une classe comme nous en avons dj vu plein, sauf quelle a la capacit dtre utilise avec nimporte quel autre type, comme les entiers, les chanes de caractres, les voitures Cela permet dviter de devoir crer une classe ListeInt, une classe ListeString, une classe ListeVoiture, etc On pourra utiliser cette classe avec tous les types grce aux chevrons : Code : C# List<string> listeChaine = new List<string>(); List<int> listeEntier = new List<int>(); List<Voiture> listeVoiture = new List<Voiture>();

Nous indiquons entre les chevrons le type qui sera utilis avec le type gnrique. Oui mais, si nous voulons pouvoir mettre nimporte quel type dobjet dans une liste, il suffirait de crer une ListeObject ? Puisque tous les objets drivent d'object En fait, cest le choix qui avait t fait dans la toute premire version de .NET. On utilisait lobjet ArrayList qui possde une mthode Add prenant en paramtre un object. Cela fonctionne. Sauf que nous nous trouvions faces des limitations : Premirement, nous pouvions mlanger nimporte quel type dobjet dans la liste, des entiers, des voitures, des chiens, etc. Cela devenait une classe fourre-tout et nous ne savions jamais ce quil y avait dans la liste. Deuximement, mme si nous savions quil ny avait que des entiers dans la liste, nous tions obligs de le traiter en tant quobject et donc dutiliser le boxing et lunboxing pour mettre les objets dans la liste ou pour les rcuprer. Cela engendrait donc confusion et perte de performance. Grce aux gnriques, il devenait donc possible de crer des listes de nimporte quel type et nous tions certains du type que nous allions rcuprer dans la liste.

Les types gnriques du framework .NET


Le framework .NET possde beaucoup de classes et dinterfaces gnriques, notamment dans lespace de nom System.Collections.Generic. La liste est la classe gnrique que vous utiliserez srement le plus. Mais beaucoup dautres sont votre disposition. Citons par exemple la classe Queue<> qui permet de grer une file dattente style FIFO (first in, first out : premier entr, premier sorti) : Code : C# Queue<int> file = new Queue<int>(); file.Enqueue(3); file.Enqueue(1); int valeur = file.Dequeue(); // valeur contient 3 valeur = file.Dequeue(); // valeur contient 1

Citons encore le dictionnaire dlment qui est une espce dannuaire o lon accde aux lments grce une cl : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Dictionary<string, Personne> annuaire = new Dictionary<string, Personne>(); annuaire.Add("06 01 02 03 04", new Personne { Prenom = "Nicolas"}); annuaire.Add("06 06 06 06 06", new Personne { Prenom = "Jeremie" }); Personne p = annuaire["06 06 06 06 06"]; // p contient la proprit Prenom valant Jeremie

240/381

Loin de moi lide de vous numrer toutes les collections gnriques du framework .NET, le but est de vous montrer rapidement quil existe beaucoup de classes gnriques dans le framework .NET.

Crer une mthode gnrique


Nous commenons cerner lintrt des gnriques. Sachez quil est bien sr possible de crer vos propres classes gnriques ou vos propres mthodes. Commenons par les mthodes, cela sera plus simple. Il est globalement intressant dutiliser un type gnrique partout o nous pourrions avoir un object. Nous avions cr une classe AfficheRepresentation() qui prenait un objet en paramtres, ce qui pourrait tre : Code : C# public static class Afficheur { public static void Affiche(object o) { Console.WriteLine("Afficheur d'objet :"); Console.WriteLine("\tType : " + o.GetType()); Console.WriteLine("\tReprsentation : " + o.ToString()); } }

Nous avons ici utilis une classe statique permettant dafficher le type dun objet et sa reprsentation. Nous pouvons lutiliser ainsi : Code : C# int i = 5; double d = 9.5; string s = "abcd"; Voiture v = new Voiture(); Afficheur.Affiche(i); Afficheur.Affiche(d); Afficheur.Affiche(s); Afficheur.Affiche(v);

Rappelez-vous, chaque fois quon passe dans cette mthode, lobjet est box en type object quand il sagit dun type valeur. Nous pouvons amliorer cette mthode en crant une mthode gnrique. Regardons ce code : Code : C# public static class Afficheur { public static void Affiche<T>(T a) { Console.WriteLine("Afficheur d'objet :"); Console.WriteLine("\tType : " + a.GetType());

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} Console.WriteLine("\tReprsentation : " + a.ToString());

241/381

Cette mthode fait exactement la mme chose mais avec les gnriques. Dans un premier temps, la mthode annonce quelle va utiliser un type gnrique reprsent par la lettre T entre chevrons. Il est conventionnel que les types gnriques soient utiliss avec T.

Cela veut dire que tout type utilis dans cette mthode dclar avec T sera du type pass la mthode. Ainsi, la variable a est du type gnrique qui sera prcis lors de lappel cette mthode. Comme a est un objet, nous pouvons appeler la mthode GetType() et la mthode ToString() sur cet objet. Pour afficher un objet, nous pourrons faire : Code : C# int i = 5; double d = 9.5; string s = "abcd"; Voiture v = new Voiture(); Afficheur.Affiche<int>(i); Afficheur.Affiche<double>(d); Afficheur.Affiche<string>(s); Afficheur.Affiche<Voiture>(v);

Dans le premier appel, nous indiquons que nous souhaitons afficher i dont le type gnrique est int. Ce quil se passe, cest comme si le CLR crait la surcharge de la mthode Affiche, prenant un entier en paramtre : Code : C# public static void Affiche(int a) { Console.WriteLine("Afficheur d'objet :"); Console.WriteLine("\tType : " + a.GetType()); Console.WriteLine("\tReprsentation : " + a.ToString()); }

De mme pour laffichage suivant, o lon indique le type double entre les chevrons. Cest comme si le CLR crait la surcharge prenant un double en paramtre : Code : C# public static void Affiche(double a) { Console.WriteLine("Afficheur d'objet :"); Console.WriteLine("\tType : " + a.GetType()); Console.WriteLine("\tReprsentation : " + a.ToString()); }

Et ceci pour tous les types utiliss, savoir ici int, double, string et Voiture. noter que dans cet exemple, nous pouvons remplacer les quatre lignes suivantes :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# Afficheur.Affiche<int>(i); Afficheur.Affiche<double>(d); Afficheur.Affiche<string>(s); Afficheur.Affiche<Voiture>(v);

242/381

Par : Code : C# Afficheur.Affiche(i); Afficheur.Affiche(d); Afficheur.Affiche(s); Afficheur.Affiche(v);

En effet, nul besoin de prciser quel type nous souhaitons traiter ici, le compilateur est assez malin pour le dduire du type de la variable. La variable i tant un entier, il est obligatoire que le type gnrique soit un entier. Il est donc facultatif ici de le prciser. Une fois quil est prcis entre les chevrons, le type gnrique sutilise dans la mthode comme nimporte quel autre type. Nous pouvons avoir autant de paramtres gnriques que nous le voulons dans les paramtres et utiliser le type gnrique dans le corps de la mthode. Par exemple la mthode suivante : Code : C# public static void Echanger<T>(ref T t1, ref T t2) { T temp = t1; t1 = t2; t2 = temp; }

permet dchanger le contenu de deux variables entre elles. Cest donc une mthode gnrique puisquelle prcise entre les chevrons que nous pourrons utiliser le type T. En paramtres de la mthode, nous passons deux variables de types gnriques. Dans le corps de la mthode, nous crons une variable du type gnrique qui sert de mmoire temporaire puis nous changeons les rfrences des deux variables. Nous pourrons utiliser cette mthode ainsi : Code : C# int i = 5; int j = 10; Echanger(ref i, ref j); Console.WriteLine(i); Console.WriteLine(j); Voiture v1 = new Voiture { Couleur = "Rouge" }; Voiture v2 = new Voiture { Couleur = "Verte" }; Echanger(ref v1, ref v2); Console.WriteLine(v1.Couleur); Console.WriteLine(v2.Couleur);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Qui donnera : Code : Console 10 5 Verte Rouge

243/381

Il est bien sr possible de crer des mthodes prenant en paramtres plusieurs types gnriques diffrents. Il suffit alors de prciser autant de types diffrents entre les chevrons quil y a de types gnriques diffrents : Code : C# static void Main(string[] args) { int i = 5; int j = 5; double d = 9.5; Console.WriteLine(EstEgal(i, j)); Console.WriteLine(EstEgal(i, d));

} public static bool EstEgal<T, U>(T t, U u) { return t.Equals(u); }

Ici, la mthode EstEgal() prend en paramtres potentiellement deux types diffrents. Nous lappelons une premire fois avec deux entiers et ensuite avec un entier et un double.

Crer une classe gnrique


Une classe gnrique fonctionne comme pour les mthodes. Cest une classe o nous pouvons indiquer de 1 N types gnriques. Cest comme cela que fonctionne la liste que nous avons dj beaucoup manipule. En fait, la liste nest quune espce de tableau volu. Nous pourrions trs bien imaginer crer notre propre liste sur ce principe, sachant que cest compltement absurde car elle sera forcment moins bien que cette classe, mais cest pour ltude. Le principe est davoir un tableau plus ou moins dynamique qui grossit si jamais le nombre dlments devient trop grand pour sa capacit. Pour dclarer une classe gnrique, nous utiliserons nouveau les chevrons la fin de la ligne qui dclare la classe : Code : C# public class MaListeGenerique<T> { }

Nous allons raliser une implmentation toute basique de cette classe histoire de voir un peu quoi ressemble une classe gnrique. Cette classe na dintrt que pour tudier les gnriques, vous lui prfrerez videmment la classe List<> du framework .NET. Nous avons besoin de trois variables prives. La capacit de la liste, le nombre dlments dans la liste et le tableau gnrique. Code : C# public class MaListeGenerique<T>

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ private int capacite; private int nbElements; private T[] tableau; public MaListeGenerique() { capacite = 10; nbElements = 0; tableau = new T[capacite]; }

244/381

Notons la dclaration du tableau. Il utilise le type gnrique. Concrtement, cela veut dire que quand nous utiliserons la liste avec un entier, nous aurons un tableau dentiers. Lorsque nous utiliserons la liste avec un objet Voiture, nous aurons un tableau de Voiture, etc. Nous initialisons ces variables membres dans le constructeur, en dcidant compltement arbitrairement que la capacit par dfaut de notre liste est de 10 lments. La dernire ligne instancie le tableau en lui indiquant sa taille. Il reste implmenter lajout dans la liste : Code : C# public class MaListeGenerique<T> { [Code enlev pour plus de clart] public void Ajouter(T element) { if (nbElements >= capacite) { capacite *= 2; T[] copieTableau = new T[capacite]; for (int i = 0; i < tableau.Length; i++) { copieTableau[i] = tableau[i]; } tableau = copieTableau; } tableau[nbElements] = element; nbElements++; }

Il sagit simplement de mettre la valeur que lon souhaite ajouter lemplacement adquat dans le tableau. Nous le mettons en dernire position, c'est--dire lemplacement correspondant au nombre dlments. Au dbut, nous avons commenc par vrifier si le nombre dlments tait suprieur la capacit du tableau. Si cest le cas, alors nous devons augmenter la capacit du tableau, jai ici dcid encore compltement arbitrairement que je doublais la capacit. Il ne reste plus qu crer un nouveau tableau de cette nouvelle capacit et copier les lments du premier tableau dans celui-ci. V ous aurez not que le paramtre de la mthode Ajouter est bien du type gnrique. Pour le plaisir, rajoutons enfin une mthode permettant de rcuprer llment un indice donn : Code : C# public class MaListeGenerique<T> { [Code enlev pour plus de clart] public T ObtenirElement(int indice)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } } return tableau[indice];

245/381

Il sagit juste daccder au tableau pour renvoyer la valeur lindice concern. Llment intressant ici est de constater que le type de retour de la mthode est bien du type gnrique. Cette liste peut sutiliser de la manire suivante : Code : C# MaListeGenerique<int> maListe = new MaListeGenerique<int>(); maListe.Ajouter(25); maListe.Ajouter(30); maListe.Ajouter(5); Console.WriteLine(maListe.ObtenirElement(0)); Console.WriteLine(maListe.ObtenirElement(1)); Console.WriteLine(maListe.ObtenirElement(2)); for (int i = 0; i < 30; i++) { maListe.Ajouter(i); }

Ici, nous utilisons la liste avec un entier, mais elle fonctionnerait tout aussi bien avec un autre type. Nhsitez pas passer en debug dans la mthode Ajouter() pour observer ce quil se passe exactement lors de laugmentation de capacit. V comment on cre une classe gnrique ! oil Une fois quon a compris que le type gnrique sutilise comme nimporte quel autre type, cela devient assez facile. Rappelez-vous, toute classe qui manipule des object est susceptible dtre amliore en utilisant les gnriques.

La valeur par dfaut dun type gnrique

V ous aurez remarqu dans limplmentation de la liste du dessus que si nous essayons dobtenir un lment du tableau un indice qui nexiste pas, nous aurons une erreur. Ce comportement est une bonne chose, il est important de grer les cas limites. En loccurrence ici, on dlgue au tableau la gestion du cas limite. On pourrait envisager de grer nous-mmes ce cas limite en affichant un message et en renvoyant une valeur nulle. Seulement, pour un objet Voiture, qui est un type rfrence, il est tout fait pertinent davoir null. Mais pour un int, qui est un type valeur, cela na pas de sens. Cest l quintervient le mot-cl default. Comme son nom lindique, il renvoie la valeur par dfaut du type. Pour un type rfrence, cest null, pour un type valeur cest 0. Ce qui donnerait : Code : C# public T ObtenirElement(int indice) { if (indice < 0 || indice >= nbElements) { Console.WriteLine("L'indice n'est pas bon"); return default(T); } return tableau[indice]; }

Les interfaces gnriques


www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

246/381

Les interfaces peuvent aussi tre gnriques. Dailleurs, a me fait penser que plus haut, je vous ai indiqu quun code tait moche et que jen parlerai plus tard Il sagissait du chapitre sur les interfaces o nous avions implments linterface IComparable. Nous souhaitions comparer des voitures entre elles et nous avions obtenu le code suivant : Code : C# public class Voiture : IComparable { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } public int CompareTo(object obj) { Voiture voiture = (Voiture)obj; return Vitesse.CompareTo(voiture.Vitesse); }

Je souhaite pouvoir comparer des voitures entre elles, mais le framework .NET me fournit un object en paramtres de la mthode CompareTo(). Quelle ide ! Comme si je voulais pouvoir comparer des voitures avec des chats ou des chiens. Cela me force en plus faire un cast. Pourquoi il ne me passe pas directement une V oiture en paramtres ? V ous le sentez venir et vous avez raison. Un object ! Berk, oserais-je dire ! Et sans parler des performances. Cest l o les gnriques vont pouvoir voler notre secours. Linterface IComparable date de la premire version du framework .NET. Le C# ne possdait pas encore les types gnriques. Depuis leur apparition, il est possible dimplmenter la version gnrique de cette interface. Pour cela, nous faisons suivre linterface du type que nous souhaitons utiliser entre les chevrons. Cela donne : Code : C# public class Voiture : IComparable<Voiture> { public string Couleur { get; set; } public string Marque { get; set; } public int Vitesse { get; set; } public int CompareTo(Voiture obj) { return Vitesse.CompareTo(obj.Vitesse); }

Nous devons toujours implmenter la mthode CompareTo() sauf que nous avons dsormais un objet V oiture en paramtres, ce qui nous vite de le caster.

Les restrictions sur les types gnriques


Une mthode ou une classe gnrique cest bien, mais peut-tre voulons-nous quelles ne fonctionnent pas avec tous les types. Aussi, le C# permet de dfinir des restrictions sur les types gnriques. Pour ce faire, on utilise le mot-cl where. Il existe 6 types de restrictions : Contrainte where T : struct where T : class where T : new() Description Le type gnrique doit tre un type valeur Le type gnrique doit tre un type rfrence Le type gnrique doit possder un constructeur par dfaut

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


where T : IMonInterface Le type gnrique doit implmenter linterface IMonInterface where T : MaClasse where T1 : T2 Le type gnrique doit driver de la classe MaClasse Le type gnrique doit driver du type gnrique T2

247/381

Par exemple, nous pouvons dfinir une restriction sur une mthode gnrique afin quelle naccepte en type gnrique que des types qui implmentent une interface. Soit linterface suivante : Code : C# public interface IVolant { void DeplierLesAiles(); void Voler(); }

Qui est implmente par deux objets : Code : C# public class Avion : IVolant { public void DeplierLesAiles() { Console.WriteLine("Je dplie mes ailes mcaniques"); } public void Voler() { Console.WriteLine("J'allume le moteur"); }

public class Oiseau : IVolant { public void DeplierLesAiles() { Console.WriteLine("Je dplie mes ailes d'oiseau"); } public void Voler() { Console.WriteLine("Je bats des ailes"); }

Nous pouvons crer une mthode gnrique qui soccupe dinstancier ces objets et dappeler les mthodes de linterface : Code : C# public static T Creer<T>() where T : IVolant, new() { T t = new T(); t.DeplierLesAiles(); t.Voler(); return t; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

248/381

Ici, la restriction se porte sur deux niveaux. Il faut dans un premier temps que le type gnrique implmente linterface IVolant et possde galement un constructeur, bref quil soit instanciable. Nous pouvons donc utiliser cette mthode de cette faon : Code : C# Oiseau oiseau = Creer<Oiseau>(); Avion a380 = Creer<Avion>();

Nous appelons la mthode Crer() avec le type gnrique Oiseau, qui implmente bien IVolant et qui est aussi instanciable. Grce cela, nous pouvons utiliser loprateur new pour crer notre type gnrique, appeler les mthodes de linterface et renvoyer linstance. Ce qui donne : Code : Console Je dplie mes ailes doiseau Je bats des ailes Je dplie mes ailes mcaniques Jallume le moteur

Si nous tentons dutiliser la mthode avec un type qui nimplmente pas linterface IVolant, comme : Code : C# Voiture v = Creer<Voiture>();

Nous aurons lerreur de compilation suivante : Code : Console Le type 'MaPremiereApplication.Voiture' ne peut pas tre utilis comme paramtre de type

Globalement, il nous dit que lobjet Voiture nimplmente pas IVolant. Oui mais dans ce cas, plutt que dutiliser une mthode gnrique, pourquoi la mthode ne renvoie pas IVolant ?

Cest une judicieuse remarque. Mais qui ncessite quelques modifications de code. En effet, il faudrait indiquer quel type instancier. Nous pourrions par exemple faire : Code : C# public enum TypeDeVolant {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Oiseau, Avion

249/381

public static IVolant Creer(TypeDeVolant type) { IVolant volant; switch (type) { case TypeDeVolant.Oiseau: volant = new Oiseau(); break; case TypeDeVolant.Avion: volant = new Avion(); break; default: return null; } volant.DeplierLesAiles(); volant.Voler(); return volant; }

Et instancier nos objets de cette faon : Code : C# Oiseau oiseau = (Oiseau)Creer(TypeDeVolant.Oiseau); Avion a380 = (Avion)Creer(TypeDeVolant.Avion);

Ce qui complique un peu les choses et rajoute des cast dont on pourrait volontiers se passer. De plus, si nous crons un nouvel objet qui implmente cette interface, il faudrait tout modifier. Avouez quavec les types gnriques, cest quand mme plus propre. Nous pouvons bien sr avoir des restrictions sur les types gnriques dune classe. Pour le montrer, nous allons crer une classe dont lobjectif est davoir des types valeur qui pourraient ne pas avoir de valeur. Pour les types rfrence, il suffit dutiliser le mot-cl null. Mais pour les types valeur comme les entiers, nous navons rien pour indiquer que ceux-ci nont pas de valeur. Par exemple : Code : C# public class TypeValeurNull<T> where T : struct { private bool aUneValeur; public bool AUneValeur { get { return aUneValeur; } } private T valeur; public T Valeur { get { if (aUneValeur) return valeur; throw new InvalidOperationException(); } set {

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


aUneValeur = true; valeur = value;

250/381

Ici, nous utilisons une classe possdant un type gnrique qui sera un type valeur, grce la condition where T : struct. Cette classe encapsule le type gnrique pour indiquer avec un boolen si le type a une valeur ou pas. Ne faites pas attention la ligne : Code : C# throw new InvalidOperationException();

qui permet juste de renvoyer une erreur, nous tudierons les exceptions un peu plus loin. Elle pourra sutiliser ainsi : Code : C# TypeValeurNull<int> entier = new TypeValeurNull<int>(); if (!entier.AUneValeur) { Console.WriteLine("l'entier n'a pas de valeur"); } entier.Valeur = 5; if (entier.AUneValeur) { Console.WriteLine("Valeur de l'entier : " + entier.Valeur); }

Et si nous souhaitons avoir pareil pour un autre type valeur, il ny a rien faire de plus : Code : C# TypeValeurNull<double> valeur = new TypeValeurNull<double>();

Cest quand mme super pratique comme classe !! Mais ne rvons-pas, cette ide ne vient pas de moi. Cest en fait une fonctionnalit du framework .NET : les types nullables.

Les types nullables


En fait, la classe que nous avons vue au-dessus existe dj dans le framework .NET, et en mieux ! videmment. Elle permet de faire exactement ce que jai dcrit, c'est--dire permettre un type valeur davoir une valeur nulle. Elle est mieux faite dans la mesure o elle tire parti de certaines fonctionnalits du framework .NET qui en simplifie lcriture. Il sagit de la classe Nullable<>. Aussi, nous pourrons crer un entier pouvant tre null grce au code suivant : Code : C# Nullable<int> entier = null; if (!entier.HasValue) { Console.WriteLine("l'entier n'a pas de valeur"); } entier = 5; if (entier.HasValue)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } Console.WriteLine("Valeur de l'entier : " + entier.Value);

251/381

Le principe est grosso modo le mme sauf que nous pouvons utiliser le mot-cl null ou affecter directement la valeur lentier en utilisant l'oprateur d'affectation, sans passer par la proprit Valeur. Il peut aussi tre compar au mot-cl null ou tre utilis avec loprateur +, etc. Ceci est possible grce certaines fonctionnalits du C# que nous navons pas vues et qui sortent de ltude de ce tutoriel. Cette classe est tellement pratique que le compilateur a t optimis pour simplifier son criture. En effet, utiliser Nullable<> est un peu long pour nous autres informaticiens qui sommes des paresseux. Aussi, lcriture : Code : C# Nullable<int> entier = null;

peut se simplifier en : Code : C# int? entier = null;

cest le point dinterrogation qui remplace la dclaration de la classe Nullable<>.

En rsum

Avec les gnriques, vous pouvez crer des mthodes ou des classes qui sont indpendantes d'un type. On les appellera des mthodes gnriques et des types gnriques. On utilise les chevrons <> pour indiquer le type d'une classe ou d'une mthode gnrique. Les interfaces peuvent aussi tre gnriques, comme l'interface IEnumerable<>. Les types nullables constituent un exemple d'utilisation trs pratique des classes gnriques.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

252/381

TP types gnriques
Ahh, un peu de pratique histoire de vrifier que nous avons bien compris les gnriques. C'est un concept assez facile apprhender mais relativement difficile mettre en uvre. Quand en ai-je besoin ? Comment ? V donc un petit exercice qui va vous permettre d'essayer de mettre en uvre une classe gnrique. oici

Instructions pour raliser la premire partie du TP


Dans la premire partie du TP, nous allons raliser une liste chane. Il sagit du grand classique des TP dinformatique en C. Je vous rappelle le principe. La liste chane permet de naviguer dlment en lment. Quand nous sommes sur le premier lment, le suivant est accessible par sa proprit Suivant. Lorsque nous accdons au suivant, llment prcdent est accessible par la proprit Precedent et le suivant toujours accessible par la proprit Suivant. Sil ny a pas de prcdent ou pas de suivant, llment est null :

Si on insre un lment la position 1, les autres se dcalent :

V oil, il faut donc crer une telle liste chane dlments. Le but est bien sr de faire en sorte que llment soit gnrique. Nhsitez pas rflchir un peu avant de vous lancer. Cela pourrait paratre un peu simpliste, mais en fait cela occasionne quelques nuds au cerveau. Toujours est-il que je souhaiterais disposer dune proprit en lecture seule permettant daccder au premier lment ainsi quune autre proprit galement en lecture seule permettant daccder au dernier lment. Bien sr, il faut pouvoir naviguer dlment en lment avec des proprits prcdent et suivant. Il faut videmment une mthode permettant dajouter un lment la fin de la liste. Nous aurons galement besoin dune mthode permettant daccder un lment partir de son indice et enfin dune mthode permettant dinsrer un lment un indice, dcalant tous les suivants. V pour la cration de la classe ! oil

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

253/381

Ensuite, notre programme instanciera notre liste chane pour lui ajouter les entiers 5, 10 et 4. Puis nous afficherons les valeurs de cette liste en nous basant sur la premire proprit et en naviguant dlment en lment. Nous afficherons ensuite les diffrents lments en utilisant la mthode daccs un lment par son indice. Enfin, nous insrerons la valeur 99 la premire position (position 0), puis la valeur 33 la deuxime position et enfin la valeur 30 nouveau la deuxime position. Puis nous afficherons tout ce beau monde. Fin de lnonc, ouf ! Pour ceux qui nont pas besoin daide, les explications sont termines. Ouvrez vos Visual C# Express (ou vos Visual Studio si vous tes riches ) et vos claviers. Pour les autres, je vais essayer de vous guider un peu plus en essayant tout de mme de ne pas trop vous donner dindications non plus. En fait, votre liste chaine nest pas vraiment une liste, comme pourrait ltre la List<> que nous connaissons. Cette liste chaine possde un point dentre qui est le premier lment. Lajout du premier lment est trs simple, il suffit de mettre jour une proprit. Pour ajouter llment suivant, il faut en fait brancher la proprit Suivant du premier lment llment que nous sommes en train dajouter. Et inversement, la proprit Precedent de llment que nous souhaitons ajouter sera mise jour avec le premier lment. On se rend compte que llment est un peu plus complexe quun simple type. Nous allons donc avoir une classe gnrique possdant trois proprits (Precedent, Suivant et Valeur). Et nous aurons galement une classe du mme type gnrique possdant la proprit Premier et la proprit Dernier et les mthodes dajout, dobtention de llment et dinsertion. Allez, je vous en ai assez dit. vous de jouer !

Correction
Pas si facile hein ? Mais bon, comme vous tes super entrains, cela na pas d vous poser trop de problmes. V la correction que je propose. oici La premire chose faire est de crer la classe gnrique permettant de stocker un lment : Code : C# public class Chainage<T> { public Chainage<T> Precedent { get; set; } public Chainage<T> Suivant { get; set; } public T Valeur { get; set; } }

Cest une classe gnrique toute simple qui possde une valeur du type gnrique et deux proprits du mme type que llment pour obtenir le prcdent ou le suivant. Peut-tre que la plus grande difficult rside ici, de bien modliser la classe qui permet dencapsuler llment. Il faudra ensuite crer la liste gnrique et ses mthodes : Code : C# public class ListeChainee<T> { }

La liste chaine possde galement un type gnrique. Nous crons sa proprit Premier : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public class ListeChainee<T> { public Chainage<T> Premier { get; private set; } }

254/381

L, cest trs simple, il sagit juste dune proprit en lecture seule stockant le premier lment. Cest la mthode Ajouter() qui permettra de mettre jour cette valeur. Notez quand mme que nous utilisons le type gnrique comme type gnrique de la classe encapsulante. Par contre, pour la proprit Dernier, cest un peu plus compliqu. Pour la retrouver, nous allons parcourir tous les lments partir de la proprit Premier. Ce qui donne : Code : C# public class ListeChainee<T> { [Code supprim pour plus de clart] public Chainage<T> Dernier { get { if (Premier == null) return null; Chainage<T> dernier = Premier; while (dernier.Suivant != null) { dernier = dernier.Suivant; } return dernier; } }

On parcourt les lments en bouclant sur la proprit Suivant, tant que celle-ci nest pas nulle. Il sagit l dun parcours assez classique o on utilise une variable temporaire qui passe au suivant chaque itration. Nous pouvons prsent crer la mthode Ajouter : Code : C# public class ListeChainee<T> { [Code supprim pour plus de clart] public void Ajouter(T element) { if (Premier == null) { Premier = new Chainage<T> { Valeur = element }; } else { Chainage<T> dernier = Dernier; dernier.Suivant = new Chainage<T> { Valeur = element, Precedent = dernier }; } } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

255/381

Cette mthode traite dans un premier temps le cas du premier lment. Il sagit simplement de mettre jour la proprit Premier. De mme, grce au calcul interne de la proprit Dernier, il sera facile dajouter un nouvel lment en se branchant sur la proprit Suivant du dernier lment. Notez que vu que nous ne la renseignons pas, la proprit Suivant du nouvel lment sera bien null. Pour obtenir un lment un indice donn, il suffira de reprendre le mme principe que lors du parcours pour obtenir le dernier lment, sauf quil faudra sarrter au bon moment : Code : C# public class ListeChainee<T> { [Code supprim pour plus de clart] public Chainage<T> ObtenirElement(int indice) { Chainage<T> temp = Premier; for (int i = 1; i <= indice; i++) { if (temp == null) return null; temp = temp.Suivant; } return temp; }

Ici, plusieurs solutions. Jai choisi dutiliser une boucle for. Nous aurions trs bien pu garder la boucle while comme pour la proprit Dernier. Enfin, il ne reste plus qu insrer un lment : Code : C# public class ListeChainee<T> { [Code supprim pour plus de clart] public void Inserer(T element, int indice) { if (indice == 0) { Chainage<T> temp = Premier; Premier = new Chainage<T> { Suivant = temp, Valeur = element }; temp.Precedent = Premier; } else { Chainage<T> elementAIndice = ObtenirElement(indice); if (elementAIndice == null) Ajouter(element); else { Chainage<T> precedent = elementAIndice.Precedent; Chainage<T> temp = precedent.Suivant; precedent.Suivant = new Chainage<T> { Valeur = element, Precedent = precedent, Suivant = temp }; } } } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

256/381

Nous traitons dans un premier temps le cas o lon doit insrer l'en-tte. Il suffit de mettre jour la valeur du premier en ayant au pralable dcal ce dernier dun cran. Attention, si Premier est null, nous allons avoir un problme. Dans ce cas, soit nous laissons le problme, en effet, peut-on vraiment insrer un lment avant les autres s'il n'y en a pas ? Soit nous grons le cas et dcidons d'insrer l'lment en tant que Premier : Code : C# public class ListeChainee<T> { [Code supprim pour plus de clart] public void Inserer(T element, int indice) { if (indice == 0) { if (Premier == null) Premier = new Chainage<T> { Valeur = element }; else { Chainage<T> temp = Premier; Premier = new Chainage<T> { Suivant = temp, Valeur = element }; temp.Precedent = Premier; } } else { Chainage<T> elementAIndice = ObtenirElement(indice); if (elementAIndice == null) Ajouter(element); else { Chainage<T> precedent = elementAIndice.Precedent; Chainage<T> temp = precedent.Suivant; precedent.Suivant = new Chainage<T> { Valeur = element, Precedent = precedent, Suivant = temp }; } } } }

Pour les autres cas, si nous tentons dinsrer un indice qui nexiste pas, nous insrons la fin en utilisant la mthode Ajouter() existante. Sinon, on intercale le nouvel lment dans la liste en prenant soin de brancher le prcdent sur notre nouvel lment et de brancher le suivant sur notre nouvel lment. V pour notre classe. oil Reste utiliser notre classe : Code : C# static void Main(string[] args) { ListeChainee<int> listeChainee = new ListeChainee<int>(); listeChainee.Ajouter(5); listeChainee.Ajouter(10); listeChainee.Ajouter(4); Console.WriteLine(listeChainee.Premier.Valeur); Console.WriteLine(listeChainee.Premier.Suivant.Valeur); Console.WriteLine(listeChainee.Premier.Suivant.Suivant.Valeur); Console.WriteLine("*************"); Console.WriteLine(listeChainee.ObtenirElement(0).Valeur); Console.WriteLine(listeChainee.ObtenirElement(1).Valeur);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Console.WriteLine(listeChainee.ObtenirElement(2).Valeur); Console.WriteLine("*************"); listeChainee.Inserer(99, 0); listeChainee.Inserer(33, 2); listeChainee.Inserer(30, 2); Console.WriteLine(listeChainee.ObtenirElement(0).Valeur); Console.WriteLine(listeChainee.ObtenirElement(1).Valeur); Console.WriteLine(listeChainee.ObtenirElement(2).Valeur); Console.WriteLine(listeChainee.ObtenirElement(3).Valeur); Console.WriteLine(listeChainee.ObtenirElement(4).Valeur); Console.WriteLine(listeChainee.ObtenirElement(5).Valeur);

257/381

Ce qui nous donnera :

Instructions pour raliser la deuxime partie du TP


Bon, cest trs bien de pouvoir accder un lment par son indice. Mais une liste sur laquelle on ne peut pas faire un foreach, cest quand mme bien dommage. Attaquons dsormais la deuxime partie du TP. Toujours dans loptique de manipuler les gnriques, nous allons faire en sorte que notre liste chaine puisse tre parcourable en utilisant un foreach. Nous avons dit plus haut quil suffisait dimplmenter linterface IEnumerable. En loccurrence, nous allons implmenter sa version gnrique, vu que nous travaillons avec une classe gnrique. V le but de ce TP. Si vous vous le sentez, allez-y ! oil Je pense par contre que vous allez avoir besoin dtre un peu guids car cest une opration un peu particulire. V ous laurez devin, il faut que notre liste implmente linterface IEnumerable<T>. Le fait dimplmenter cette interface va vous forcer implmenter deux mthodes GetEnumerator(), la version normale et la version explicite. Sachez ds prsent que les deux mthodes feront exactement la mme chose. Mais, quest-ce quil raconte ? Implmenter une interface explicitement ? On na jamais vu a !

Cest vrai ! Allez, je vous en parle aprs la correction. Pour linstant, cela ne devrait pas vous perturber car les deux mthodes font exactement la mme chose. En loccurrence, elles renverront un Enumerator personnalis. Il va donc falloir crer cet Enumerator qui va soccuper de la mcanique permettant de naviguer dans notre liste. Il sagit

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


dune nouvelle classe qui va devoir implmenter linterface IEnumerator<T>, cest--dire : Code : C# public class ListeChaineeEnumerator<T> : IEnumerator<T> { }

258/381

Cette interface permet dindiquer que notre enumrateur va respecter le contrat lui permettant de fonctionner avec un foreach. Avec cette interface, vous allez devoir implmenter : La proprit Current. La proprit explicite Current (qui sera la mme chose que la prcdente). La mthode MoveNext qui permet de passer llment suivant. La mthode Reset, qui permet de revenir au dbut de la liste. Et la mthode Dispose.

La mthode Dispose est en fait hrite de linterface IDisposable dont hrite linterface IEnumerator<T>. Cest une interface particulire qui offre lopportunit de faire tout ce quil faut pour nettoyer la classe, cest--dire librer les variables qui en auraient besoin. En loccurrence, ici nous naurons rien faire mais il faut quand mme que la mthode soit prsente. Elle sera donc vide. Pour implmenter les autres mthodes, il faut que lnumrateur connaisse la liste quil doit numrer. Il faudra donc que la classe ListeChaineeEnumerator prenne en paramtre de son constructeur la liste numrer. Dans ce constructeur, on initialise la variable membre indice qui contient lindice courant. La proprit Current renverra llment lindice courant. La mthode MoveNext passe llment suivant et renvoie faux sil ny a plus dlments, vrai sinon. Enfin la mthode Reset repasse lindice sa valeur initiale. noter que la valeur initiale de lindice est -1, car la boucle foreach commence par appeler la mthode MoveNext qui commence par aller llment suivant, cest--dire llment 0. Il ne reste plus qu vous dire exactement quoi mettre dans les mthodes GetEnumerator de la liste chaine, car vous ne trouverez peut-tre pas du premier coup : Code : C# public IEnumerator<T> GetEnumerator() { return new ListeChaineeEnumerator<T>(this); } IEnumerator IEnumerable.GetEnumerator() { return new ListeChaineeEnumerator<T>(this); }

Cest vous de jouer pour la suite.

Correction
Encore moins facile. Tant quon ne la pas fait une premire fois, implmenter linterface IEnumerable est un peu droutant. Aprs, cest toujours pareil. V donc ma correction. Tout dabord, la liste chane doit implmenter IEnumerable<T>, ce qui donne : oici Code : C# public class ListeChainee<T> : IEnumerable<T> { [Code identique au TP prcdent]

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public IEnumerator<T> GetEnumerator() { return new ListeChaineeEnumerator<T>(this); } IEnumerator IEnumerable.GetEnumerator() { return new ListeChaineeEnumerator<T>(this); }

259/381

L, cest du tout cuit vu que je vous avais donn la solution un peu plus tt !

Jespre que vous avez au moins russi a.

Maintenant, il faut donc crer un nouvel numrateur personnalis en lui passant notre liste chaine en paramtres. Cet numrateur doit implmenter linterface IEnumerator, ce qui donne : Code : C# public class ListeChaineeEnumerator<T> : IEnumerator<T> { }

Comme prvu, il faut donc un constructeur qui prend en paramtre la liste chaine : Code : C# public class ListeChaineeEnumerator<T> : IEnumerator<T> { private int indice; private ListeChainee<T> listeChainee; public ListeChaineeEnumerator(ListeChainee<T> liste) { indice = -1; listeChainee = liste; } public void Dispose() { }

Cette liste sera enregistre dans une variable membre de la classe. Tant que nous y sommes, nous ajoutons un indice priv que nous initialisons -1, comme dj expliqu. Notez galement que la mthode Dispose() est vide. Reste implmenter le reste des mthodes : Code : C# public class ListeChaineeEnumerator<T> : IEnumerator<T> { private int indice; private ListeChainee<T> listeChainee; public ListeChaineeEnumerator(ListeChainee<T> liste) { indice = -1; listeChainee = liste; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public void Dispose() { } public bool MoveNext() { indice++; Chainage<T> element = listeChainee.ObtenirElement(indice); return element != null; } public T Current { get { Chainage<T> element = listeChainee.ObtenirElement(indice); if (element == null) return default(T); return element.Valeur; } } object IEnumerator.Current { get { return Current; } } public void Reset() { indice = -1; }

260/381

Commenons par la mthode MoveNext(). Elle passe lindice suivant et renvoie faux ou vrai en fonction de si on arrive au bout de la liste ou pas. Noubliez pas que cest la premire mthode qui sera appele dans le foreach, donc pour passer llment suivant, on incrmente lindice pour le positionner llment 0. Cest pour cela que lindice a t initialis -1. On utilise ensuite la mthode existante de la liste pour obtenir llment un indice afin de savoir si notre liste peut continuer snumrer. La proprit Current renvoie llment lindice courant, pour cela on utilise lindice pour accder llment courant, en utilisant les mthodes de la liste. Lautre proprit Current fait la mme chose, il suffit dappeler la proprit Current. Enfin, la mthode Reset permet de rinitialiser lnumrateur en retournant lindice initial. Finalement, ce nest pas si compliqu que a. Mais il faut avouer que la premire fois, cest un peu droutant. mon sens, cest un bon exercice pratique. Peut-tre que mes explications ont suffi vous guider. Sans doute avez-vous d regarder un peu la documentation de IEnumerable sur internet. Dans tous les cas, devoir implmenter une interface du framework .NET est une situation que vous allez frquemment devoir rencontrer. Il est bon de sy entrainer !

Aller plus loin


V ous me direz quil fallait le deviner quon avait besoin dune classe indpendante qui permettait de grer lnumrateur. En fait, ce nest pas obligatoire. On peut trs bien faire en sorte que notre classe gre la liste chaine et son numrateur. Il suffit de faire en sorte que la liste chaine implmente galement IEnumerator<T> et de grer la logique lintrieur de la classe. Par contre, ce n'est pas recommand. D'une manire gnrale il est bien qu'une classe n'ait s'occuper que d'une seule chose. On appelle cela le principe de responsabilit unique (en anglais SRP : Single Responsibility Principle). Plus une classe fait de choses et plus une modification impacte les autres choses. Ici, il est judicieux de garder le dcouplage des deux classes. Il y a quand mme une chose que l'on peut amliorer dans le code de la correction. En effet, cette liste nest pas extrmement optimise car lorsque nous obtenons un lment, nous re-parcourons toute la liste depuis le dbut, notamment dans le cas de la gestion de lnumrateur. Il pourrait tre judicieux qu chaque foreach, nous ne parcourions pas tous les lments et qu'on vite d'appeler continuellement la mthode ObtenirElement().

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Cela pourrait se faire en liminant lindice et en utilisant une variable de type Chainage<T>, par exemple : Code : C# public class ListeChaineeEnumerator<T> : IEnumerator<T> { private Chainage<T> courant; private ListeChainee<T> listeChainee; public ListeChaineeEnumerator(ListeChainee<T> liste) { courant = null; listeChainee = liste; } public void Dispose() { } public bool MoveNext() { if (courant == null) courant = listeChainee.Premier; else courant = courant.Suivant; } return courant != null;

261/381

public T Current { get { if (courant == null) return default(T); return courant.Valeur; } } object IEnumerator.Current { get { return Current; } } public void Reset() { courant = null; }

Ici, cest la variable courant qui nous permet ditrer au fur et mesure de la liste chaine. Cest le mme principe que dans la mthode ObtenirElement, sauf quon ne re-parcoure pas toute la liste chaque fois. Dans cet exemple, l'optimisation est ngligeable. Elle peut savrer intressante si notre liste grossit normment. Dans tous les cas, a ne fait pas de mal daller plus vite. Remarquons avant de terminer qu'il est possible de simplifier encore la classe grce un mot-cl que nous dcouvrirons dans la partie suivante : yield. Il permet de crer facilement des numrateurs. Ce qui fait que le code complet de la liste chaine pourra tre : Code : C# public class ListeChainee<T> : IEnumerable<T> { public Chainage<T> Premier { get; private set; } public Chainage<T> Dernier

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ get {

262/381

if (Premier == null) return null; Chainage<T> dernier = Premier; while (dernier.Suivant != null) { dernier = dernier.Suivant; } return dernier;

public void Ajouter(T element) { if (Premier == null) { Premier = new Chainage<T> { Valeur = element }; } else { Chainage<T> dernier = Dernier; dernier.Suivant = new Chainage<T> { Valeur = element, Precedent = dernier }; } } public Chainage<T> ObtenirElement(int indice) { Chainage<T> temp = Premier; for (int i = 1; i <= indice; i++) { if (temp == null) return null; temp = temp.Suivant; } return temp; } public void Inserer(T element, int indice) { if (indice == 0) { if (Premier == null) Premier = new Chainage<T> { Valeur = element }; else { Chainage<T> temp = Premier; Premier = new Chainage<T> { Suivant = temp, Valeur = element }; temp.Precedent = Premier; } } else { Chainage<T> elementAIndice = ObtenirElement(indice); if (elementAIndice == null) Ajouter(element); else { Chainage<T> precedent = elementAIndice.Precedent; Chainage<T> temp = precedent.Suivant; precedent.Suivant = new Chainage<T> { Valeur = element, Precedent = precedent, Suivant = temp }; } } } public IEnumerator<T> GetEnumerator()

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ Chainage<T> courant = Premier; while (courant != null) { yield return courant.Valeur; courant = courant.Suivant; }

263/381

IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

Remarquons que nous n'avons plus besoin de la classe ListeChaineeEnumerator. L'implmentation devient trs facile. Nous reviendrons sur ce mot-cl dans la partie suivante.

Implmenter une interface explicitement


Jen profite ici pour faire un apart sur limplmentation dinterface explicite. Jai choisi dlibrment de ne pas le mettre dans le chapitre des interfaces car cest un cas relativement rare mais qui se produit justement quand on implmente linterface IEnumerable<T>. Cela vient du fait que linterface IEnumerable, non gnrique, expose une proprit Current. De mme, linterface IEnumerable<T>, gnrique, qui hrite de IEnumerable, expose galement une proprit Current. Il y a donc une ambigut car les deux proprits portent le mme nom, mais ne renvoient pas la mme chose. Ce qui est contraire aux rgles que nous avons dj vues. Pour faire la diffrence, il suffira de prfixer la proprit par le nom de linterface et de ne pas mettre le mot-cl public. Limplmentation explicite a galement un intrt dans le code suivant : Code : C# public interface ICarnivore { void Manger(); } public interface IFrugivore { void Manger(); } public class Homme : ICarnivore, IFrugivore { public void Manger() { Console.WriteLine("Je mange"); } } class Program { static void Main(string[] args) { Homme homme = new Homme(); homme.Manger(); ((ICarnivore)homme).Manger(); ((IFrugivore)homme).Manger(); } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

264/381

Ici, ce code compile car la classe Homme implmente la mthode Manger qui est commune aux deux interfaces. Par contre, il nest pas possible de faire la distinction entre le fait de manger en tant quhomme, en tant que ICarnivore ou en tant que IFrugivore. Ce code affichera : Code : Console Je mange Je mange Je mange

Si cest le comportement attendu, tant mieux. Si ce nest pas le cas, il va falloir implmenter au moins une des interfaces de manire explicite : Code : C# public class Homme : ICarnivore, IFrugivore { public void Manger() { Console.WriteLine("Je mange"); } void IFrugivore.Manger() { Console.WriteLine("Je mange en tant que IFrugivore"); } void ICarnivore.Manger() { Console.WriteLine("Je mange en tant que ICarnivore"); }

Avec ce code, notre exemple affichera : Code : Console Je mange Je mange en tant que ICarnivore Je mange en tant que IFrugivore

Si vous vous rappelez, nous avions vu au moment du chapitre sur les interfaces que Visual C# Express nous proposait de nous aider dans limplmentation de linterface. Par le bouton droit, vous aviez galement accs sous menu implmenter linterface explicitement . V ous pouvez vous en servir dans ce cas prcis. Je marrte l sur limplmentation dinterface explicite, mme sil y aurait dautres points voir. Globalement dans la vraie vie, ils ne vous serviront jamais. V pour ce TP. Nous avons cr une classe gnrique permettant de grer les listes chaines. Ceci nous a permis de manipuler oil ces types -combien indispensables et de nous entrainer la gnricit. Nous en avons mme profit pour voir comment faire en sorte quune classe soit numrable, en implmentant la version gnrique de IEnumerable. Notez bien sr que cette classe est fonctionnellement incomplte. Il aurait t judicieux de rajouter une mthode permettant de supprimer un lment par exemple. Dailleurs, nhsitez pas la crer et la proposer si vous souhaitez continuer vous entrainer. Dautres mthodes pourraient tre intressantes, comme vider la liste dun seul coup

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Jespre que ce TP na pas t trop compliqu raliser. noter quune classe qui fait peu prs le mme travail existe dans le framework .NET, elle sappelle LinkedList.

265/381

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

266/381

Les mthodes d'extension


En gnral, pour ajouter des fonctionnalits une classe, nous pourrons soit modifier le code source de la classe, soit crer une classe drive de notre classe et ajouter ces fonctionnalits. Dans ce chapitre nous allons voir qu'il existe un autre moyen pour tendre une classe : ceci est possible grce aux mthodes d'extension. Elles sont intressantes si nous n'avons pas la main sur le code source de la classe ou si la classe n'est pas drivable. Partons la dcouverte de ces fameuses mthodes

Qu'est-ce qu'une mthode d'extension


Comme son nom lindique, une mthode dextension permet dtendre une classe en lui rajoutant des mthodes. Ceci est pratique lorsque nous ne possdons pas le code source dune classe et quil savre difficile de la modifier. Dune manire gnrale, lorsque lon souhaite modifier une classe dont on na pas le code source, on utilise une classe drive. Ceci est impossible avec des objets qui ne sont pas drivables, comme cest le cas pour les structures comme int ou double. Mais galement comme cest le cas pour la classe String. En effet, String nest pas drivable. Nous verrons plus tard comment cela est possible, mais pour linstant, admettons-le. Si vous ne me croyez pas, vous pouvez toujours tenter de compiler le code suivant : Code : C# public class StringEvoluee : String { }

Crer une mthode d'extension


Si par exemple nous souhaitons crer une mthode permettant de crypter une chaine de caractres dans un format que nous seuls comprenons, il serait judicieux de crer une mthode dans une classe StringCryptee qui drive de string. Comme ceci nest pas possible, la seule chose qui nous reste cest de crer une mthode statique utilitaire faisant cet encodage : Code : C# class Program { static void Main(string[] args) { string chaineNormale = "Bonjour tous"; string chaineCryptee = Encodage.Crypte(chaineNormale); Console.WriteLine(chaineCryptee); chaineNormale = Encodage.Decrypte(chaineCryptee); Console.WriteLine(chaineNormale); } } public static class Encodage { public static string Crypte(string chaine) { return Convert.ToBase64String(Encoding.Default.GetBytes(chaine)); } public static string Decrypte(string chaine) { return Encoding.Default.GetString(Convert.FromBase64String(chaine)); } }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

267/381

Bon, ok, notre encodage secret ne lest pas tant que a . Il savre que jutilise ici un encodage en base 64, algorithme archi connu. Mais bon, cest pour lexemple.

Utiliser une mthode d'extension


Ces mthodes statiques jouent bien leur rle. Mais il est possible de faire en sorte que ces deux mthodes deviennent des mthodes dextensions de la classe string. Il suffit dutiliser le mot-cl this devant le premier paramtre de la mthode afin de crer une mthode dextension : Code : C# public static class Encodage { public static string Crypte(this string chaine) { return Convert.ToBase64String(Encoding.Default.GetBytes(chaine)); } public static string Decrypte(this string chaine) { return Encoding.Default.GetString(Convert.FromBase64String(chaine)); } }

Nous pourrons dsormais utiliser ces mthodes comme si elles faisaient parties de la classe String : Code : C# string chaineNormale = "Bonjour tous"; string chaineCryptee = chaineNormale.Crypte(); Console.WriteLine(chaineCryptee); chaineNormale = chaineCryptee.Decrypte(); Console.WriteLine(chaineNormale);

Pas mal non ? De plus, si nous regardons dans la compltion automatique, nous pourrons voir apparatre nos fameuses mthodes :

Plutt pratique.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

268/381

videmment, en crant une mthode dextension, nous navons bien sr pas accs aux mthodes prives ou variables membres internes la classe. La preuve, les mthodes dextensions sont des mthodes statiques qui travaillent hors de toute instance de classe. Ces mthodes doivent donc tre statiques et situes lintrieur dune classe statique.

Par contre, il faut faire attention lespace de nom o se situent nos mthodes dextensions. Si le using correspondant nest pas inclus, nous ne verrons pas les mthodes dextension. Remarquez que les mthodes dextension fonctionnent aussi avec les interfaces. Plus prcisment, elles viennent tendre toutes les classes qui implmentent une interface. Par exemple, avec deux classes implmentant linterface IVolant : Code : C# public interface IVolant { void Voler(); } public class Oiseau : IVolant { public void Voler() { Console.WriteLine("Je vole"); } } public class Avion : IVolant { public void Voler() { Console.WriteLine("Je vole"); } }

si je cre une mthode dextension prenant en paramtres un IVolant, prfix par this : Code : C# public static class Extentions { public static void Atterir(this IVolant volant) { Console.WriteLine("J'attris"); } }

je pourrais accder cette mthode pour les objets Avion et Oiseau : Code : C# Avion a = new Avion(); Oiseau b = new Oiseau(); a.Atterir(); b.Atterir();

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

269/381

noter que le framework .NET se sert de ceci pour proposer un grand nombre de mthodes dextension sur les objets implmentant IEnumerable, nous les tudierons un peu plus tard.

En rsum

Une mthode d'extension permet d'tendre une classe en lui rajoutant des mthodes. Il n'est pas recommand d'utiliser des mthodes d'extension lorsqu'on dispose dj du code source de la classe ou qu'on peut facilement en crer un type driv. On utilise le mot-cl this en premier paramtre d'une classe statique pour tendre une classe.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

270/381

Dlgus, vnements et expressions lambdas


Dans ce chapitre, nous allons aborder les dlgus, les vnements et les expressions lambdas. Les dlgus et les vnements sont des types du framework .NET que nous n'avons pas encore vus. Ils permettent d'adresser des solutions notamment dans le cadre d'une programmation par vnements, comme c'est le cas lorsque nous ralisons des applications ncessitant de ragir une action faite par un utilisateur. Nous verrons dans ce chapitre que les expressions lambdas vont de pair avec les dlgus.

Les dlgus (delegate)


Les dlgus (en anglais delegate) en C# ne soccupent pas de la classe, ni du personnel... Ils permettent de crer des variables spciales. Ce sont des variables qui pointent vers une mthode. Cest un peu comme les pointeurs de fonctions en C ou C++, sauf quici on sait exactement ce que lon utilise, car le C# est un langage fortement typ. Le dlgu va nous permettre de dfinir une signature de mthode et avec lui, nous pourrons pointer vers nimporte quelle mthode qui respecte cette signature. En gnral, on utilise un dlgu quand on veut passer une mthode en paramtres dune autre mthode. Un petit exemple sera sans doute plus parlant quun long discours. Ainsi, le code suivant : Code : C# public class TrieurDeTableau { private delegate void DelegateTri(int[] tableau); }

cre un dlgu priv la classe TrieurDeTableau qui permettra de pointer vers des mthodes qui ne retournent rien (void) et qui acceptent un tableau dentier en paramtres. Cest justement le cas des mthodes TriAscendant() et TriDescendant() que nous allons rajouter la classe (a tombe bien !) : Code : C# public class TrieurDeTableau { private delegate void DelegateTri(int[] tableau); private void TriAscendant(int[] tableau) { Array.Sort(tableau); } private void TriDescendant(int[] tableau) { Array.Sort(tableau); Array.Reverse(tableau); }

V ous aurez compris que la mthode TriAscendant utilise la mthode Array.Sort pour trier un tableau par ordre croissant. Inversement, la mthode TriDescendant() trie le tableau par ordre dcroissant en triant par ordre croissant et en inversant le tableau ensuite. Il ne reste plus qu crer une mthode dans la classe permettant dutiliser le tri ascendant et le tri descendant, grce notre dlgu : Code : C# public class TrieurDeTableau

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ [Code supprim pour plus de clart] public void DemoTri(int[] tableau) { DelegateTri tri = TriAscendant; tri(tableau); foreach (int i in tableau) { Console.WriteLine(i); } Console.WriteLine(); tri = TriDescendant; tri(tableau); foreach (int i in tableau) { Console.WriteLine(i); }

271/381

Nous voyons ici que dans la mthode DemoTri nous commenons par dclarer une variable du type du dlgu DelegateTri, qui est le dlgu que nous avons cr. Puis nous faisons pointer cette variable vers la mthode TriAscendant(). Nul besoin ici dutiliser les parenthses, mais juste le nom de la mthode. Il sagit seulement dune affectation.

Nous invoquons ensuite la mthode TriAscendant() travers la variable qui va permettre de trier le tableau par ordre croissant avant dafficher son contenu. Cette fois-ci, il faut bien sr utiliser les parenthses car nous invoquons la mthode. Puis nous faisons pointer la variable vers la mthode TriDescendant() qui va nous permettre de faire la mme chose mais avec un tri dcroissant. Nous pouvons appeler cette classe de cette faon : Code : C# static void Main(string[] args) { int[] tableau = new int[] { 4, 1, 6, 10, 8, 5 }; new TrieurDeTableau().DemoTri(tableau); }

Notre code affichera au final les entiers tris par ordre croissant, puis les mmes entiers tris par ordre dcroissant. Ok, mais pourquoi utiliser ce dlgu ? On pourrait trs bien appeler dabord la mthode de tri ascendant et ensuite la mthode de tri descendant. Comme on la toujours fait ! Eh bien, lintrt ici est que le dlgu est trs souple et va permettre de rorganiser le code (on parle galement de refactoriser du code). Ainsi, en rajoutant la mthode suivante dans la classe : Code : C# private void TrierEtAfficher(int[] tableau, DelegateTri methodeDeTri) { methodeDeTri(tableau); foreach (int i in tableau)

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


{ } } Console.WriteLine(i);

272/381

Nous pourrons grandement simplifier la mthode DemoTri : Code : C# public void DemoTri(int[] tableau) { TrierEtAfficher(tableau, TriAscendant); Console.WriteLine(); TrierEtAfficher(tableau, TriDescendant); }

Ce qui produira le mme rsultat que prcdemment. Quavons-nous fait ici ? Nous avons utilis le dlgu comme paramtre dune mthode. Ce dlgu est ensuite utilis pour invoquer une mthode que nous aurons passe en paramtres. Cest ce que nous faisons en disant dutiliser la mthode TrierEtAfficher une premire fois avec la mthode TriAscendant() et une deuxime fois avec la mthode TriDescendant(). Plutt pas mal non ? Il est mme possible de dfinir la mthode qui sera utilise lintrieur de TrierEtAfficher() sans avoir lcrire compltement dans le corps de la classe. Cela peut tre utile si la mthode est voue n'tre utilise que dans cette unique situation et quelle nest jamais appele un autre endroit. Par exemple, plutt que de dfinir compltement la mthode TriAscendant(), je pourrais la dfinir directement au moment de lappel de la mthode : Code : C# public class TrieurDeTableau { private delegate void DelegateTri(int[] tableau); private void TrierEtAfficher(int[] tableau, DelegateTri methodeDeTri) { methodeDeTri(tableau); foreach (int i in tableau) { Console.WriteLine(i); } } public void DemoTri(int[] tableau) { TrierEtAfficher(tableau, delegate(int[] leTableau) { Array.Sort(leTableau); }); Console.WriteLine(); TrierEtAfficher(tableau, delegate(int[] leTableau) { Array.Sort(leTableau); Array.Reverse(leTableau); });

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} }

273/381

Ainsi, je naurai plus besoin de la mthode TriAscendant() ni de la mthode TriDescendant(). Le fait de dfinir la mthode directement au niveau du paramtre dappel est ce quon appelle utiliser une mthode anonyme . Anonyme car la mthode na pas de nom. Elle na de vie qu cet endroit-l. La syntaxe est un peu particulire, mais au lieu dutiliser une variable de type delegate qui pointe vers une mthode, cest comme si on crivait directement la mthode. On utilise le mot-cl delegate suivi de la dclaration du paramtre. videmment, le dlgu anonyme doit respecter la signature de DelegateTri que nous avons dfinie plus haut. Enfin, nous faisons suivre avec un bloc de code qui correspond au corps de la mthode anonyme. noter que le fait dutiliser le mot-cl delegate revient en fait crer une classe qui drive de System.Delegate et qui implmente la logique de base dun dlgu. Le C# nous masque tout ceci afin dtre au maximum efficace.

Diffusion multiple, le Multicast


Il faut galement savoir que le dlgu peut tre multicast, c'est dire quil peut pointer vers plusieurs mthodes. Amliorons le premier exemple : Code : C# public class TrieurDeTableau { private delegate void DelegateTri(int[] tableau); private void TriAscendant(int[] tableau) { Array.Sort(tableau); foreach (int i in tableau) { Console.WriteLine(i); } Console.WriteLine(); } private void TriDescendant(int[] tableau) { Array.Sort(tableau); Array.Reverse(tableau); foreach (int i in tableau) { Console.WriteLine(i); } } public void DemoTri(int[] tableau) { DelegateTri tri = TriAscendant; tri += TriDescendant; tri(tableau); }

Ici, jutilise Console.WriteLine directement dans chaque mthode de tri afin de bien voir le rsultat du tri du tableau. Limportant est de voir que dans la mthode DemoTri, je commence par crer un dlgu que je fais pointer vers la mthode TriAscendant. Puis jajoute ce dlgu, avec loprateur +=, une nouvelle mthode, savoir TriDescendant. Dsormais, le fait dinvoquer le dlgu va invoquer en fait les deux mthodes. Ce qui produira en sortie : Code : Console

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


1 4 5 6 8 10 10 8 6 5 4 1

274/381

Ce dtail prend toute son importance avec les vnements que nous verrons plus loin. noter que le rsultat de ce code est videmment identique en utilisant les mthodes anonymes : Code : C# public void DemoTri(int[] tableau) { DelegateTri tri = delegate(int[] leTableau) { Array.Sort(leTableau); foreach (int i in tableau) { Console.WriteLine(i); } Console.WriteLine(); }; tri += delegate(int[] leTableau) { Array.Sort(tableau); Array.Reverse(tableau); foreach (int i in tableau) { Console.WriteLine(i); } }; tri(tableau); }

Il faut quand mme remarquer que lordre dans lequel sont appeles les mthodes nest pas garanti et ne dpend pas forcment de lordre dans lequel nous les avons ajoutes au dlgu.

Les dlgus gnriques Action et Func


Cest trs bien tout a, mais cela veut dire qu chaque fois que je vais avoir besoin dutiliser un dlgu, je vais devoir crer un nouveau type en utilisant le mot-cl delegate ?

Pas forcment, cest l quinterviennent les dlgus gnriques Action et Func. Action est un dlgu qui permet de pointer vers une mthode qui ne renvoie rien et qui peut accepter jusqu 16 types diffrents. Cela veut dire que le code prcdent peut tre remplac par : Code : C# public class TrieurDeTableau { private void TrierEtAfficher(int[] tableau, Action<int[]> methodeDeTri) { methodeDeTri(tableau);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


methodeDeTri(tableau); foreach (int i in tableau) { Console.WriteLine(i); }

275/381

public void DemoTri(int[] tableau) { TrierEtAfficher(tableau, delegate(int[] leTableau) { Array.Sort(leTableau); }); Console.WriteLine(); TrierEtAfficher(tableau, delegate(int[] leTableau) { Array.Sort(tableau); Array.Reverse(tableau); });

Notez que la diffrence se situe au niveau du paramtre de la mthode TrierEtAfficher qui prend un Action<int[]>. En fait, cela est quivalent crer un dlgu qui ne renvoie rien et qui prend un tableau dentier en paramtre. Si notre mthode avait deux paramtres, il aurait suffi dutiliser la forme de Action avec plusieurs paramtres gnriques, par exemple Action<int[], string> pour avoir une mthode qui ne renvoie rien et qui prend un tableau dentier et une chaine de caractres en paramtres. Lorsque la mthode renvoie quelque chose, on peut utiliser le dlgu Func<T>, sachant quici, cest le dernier paramtre gnrique qui sera du type de retour du dlgu. Par exemple : Code : C# public class Operations { public void DemoOperations() { double division = Calcul(delegate(int a, int b) { return (double)a / (double)b; }, 4, 5); double puissance = Calcul(delegate(int a, int b) { return Math.Pow((double)a, (double)b); }, 4, 5); Console.WriteLine("Division : " + division); Console.WriteLine("Puissance : " + puissance);

private double Calcul(Func<int, int, double> methodeDeCalcul, int a, int b) { return methodeDeCalcul(a, b); } }

Ici, dans la mthode Calcul, on utilise le dlgu Func pour indiquer que la mthode prend deux entiers en paramtres et renvoie un double. Si nous utilisons cette classe avec le code suivant :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Code : C# class Program { static void Main(string[] args) { new Operations().DemoOperations(); } }

276/381

Nous aurons : Code : Console Division : 0,8 Puissance : 1024

Les expressions lambdas


Non, il ne sagit pas dune expression qui danse la lambada, mais dune faon simplifie dcrire les dlgus que nous avons vus au-dessus. Ainsi, le code suivant : Code : C# DelegateTri tri = delegate(int[] leTableau) { Array.Sort(leTableau); };

peut galement scrire de cette faon : Code : C# DelegateTri tri = (leTableau) => { Array.Sort(leTableau); };

Cette syntaxe est particulire. La variable leTableau permet de spcifier le paramtre dentre de lexpression lambda. Ce paramtre est crit entre parenthses. Ici, pas besoin dindiquer son type vu quil est connu par la signature associe au dlgu. On utilise ensuite la flche => pour dfinir lexpression lambda qui sera utilise. Elle scrit de la mme faon quune mthode, dans un bloc de code. Lexpression lambda (leTableau) => se lit : leTableau conduit . Dans le corps de la mthode, nous voyons que nous utilisons la variable leTableau de la mme faon que prcdemment. Dans ce cas prcis, il est encore possible de raccourcir lcriture car la mthode ne contient quune seule ligne, on pourra alors lcrire de cette faon : Code : C# TrierEtAfficher(tableau, leTableau => Array.Sort(leTableau));

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

277/381

Sil n'y a qu'un seul paramtre lexpression lambda, on peut omettre les parenthses.

Quand il y a deux paramtres, on les spare par une virgule. noter quon nindique nulle part le type de retour sil y en a un. Notre expression lambda remplaant le calcul de la division peut donc scrire ainsi : Code : C# double division = Calcul((a, b) => { return (double)a / (double)b; }, 4, 5);

Lorsque linstruction possde une unique ligne, on peut encore simplifier lcriture, ce qui donne : Code : C# double division = Calcul((a, b) => (double)a / (double)b, 4, 5);

Pourquoi tout ce blabla sur les delegate et les expressions lambdas ? Pour deux raisons : parce que les dlgus sont la base des vnements ; cause des mthodes dextensions LINQ.

Nous parlerons dans la partie suivante des mthodes dextensions LINQ. Quant aux vnements, explorons-les immdiatement !

Les vnements
Les vnements sont un mcanisme du C# permettant une classe dtre notifie dun changement. Par exemple, on peut vouloir sabonner un changement de prix dune voiture. La base des vnements est le dlgu. On pourra stocker dans un vnement un ou plusieurs dlgus qui pointent vers des mthodes respectant la signature de lvnement. Un vnement est dfini grce au mot-cl event. Prenons cet exemple : Code : C# public class Voiture { public delegate void DelegateDeChangementDePrix(decimal nouveauPrix); public event DelegateDeChangementDePrix ChangementDePrix; public decimal Prix { get; set; } public void PromoSurLePrix() { Prix = Prix / 2; if (ChangementDePrix != null) ChangementDePrix(Prix); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

278/381

Dans la classe Voiture, nous dfinissons un dlgu qui ne retourne rien et qui prend en paramtre un dcimal. Nous dfinissons ensuite un vnement bas sur ce dlgu, avec comme nous lavons vu, lutilisation du mot-cl event. Enfin, dans la mthode de promotion, aprs un changement de prix (division par 2), nous notifions les ventuels objets qui se seraient abonns cet vnement en invoquant lvnement et en lui fournissant en paramtre le nouveau prix. noter que nous testons dabord sil y a un abonn lvnement (en testant sil est diffrent de null) avant de le lever. Pour sabonner cet vnement, il suffit dutiliser le code suivant : Code : C# class Program { static void Main(string[] args) { new DemoEvenement().Demo(); } } public class DemoEvenement { public void Demo() { Voiture voiture = new Voiture { Prix = 10000 }; Voiture.DelegateDeChangementDePrix delegateChangementDePrix = voiture_ChangementDePrix; voiture.ChangementDePrix += delegateChangementDePrix; } voiture.PromoSurLePrix();

private void voiture_ChangementDePrix(decimal nouveauPrix) { Console.WriteLine("Le nouveau prix est de : " + nouveauPrix); } }

Nous crons une voiture, et nous crons un dlgu du mme type que lvnement. Nous le faisons pointer vers une mthode qui respecte la signature du dlgu. Ainsi, chaque changement de prix, la mthode voiture_ChangementDePrix va tre appele et le paramtre nouveauPrix possdera le nouveau prix qui vient dtre calcul. Appelons la promotion en invoquant la mthode ChangementDePrix(), nous pouvons nous rentre compte que lapplication nous affiche le nouveau prix qui est lancien divis par 2. Lorsque nous commenons crire le code qui va permettre de nous abonner lvnement, la compltion automatique nous propose facilement de crer une mthode qui respecte la signature de lvnement. Il suffit de taper lvnement de rajouter un += et il nous propose dinsrer tout automatiquement si nous appuyons sur la tabulation :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

279/381

Ce qui gnre le code suivant : Code : C# voiture.ChangementDePrix += new Voiture.DelegateDeChangementDePrix(voiture_ChangementDePrix);

ainsi que la mthode : Code : C# void voiture_ChangementDePrix(decimal nouveauPrix) { throw new NotImplementedException(); }

On peut aisment simplifier labonnement avec : Code : C# voiture.ChangementDePrix += voiture_ChangementDePrix;

comme on la dj vu. Notez que vous pouvez galement rajouter la visibilit private sur la mthode gnre afin que cela soit plus explicite. Code : C# private void voiture_ChangementDePrix(decimal nouveauPrix) { }

Lutilisation du += permet dajouter un nouveau dlgu lvnement. Il sera ventuellement possible dajouter un autre dlgu avec le mme oprateur, ainsi deux mthodes seront dsormais notifies en cas de changement de prix. Inversement, il est possible de se dsabonner dun vnement en utilisant loprateur -= . Les vnements sont beaucoup utiliss dans les applications en C#, comme les applications clients lourds dveloppes avec WPF par exemple. Ce sont des applications comme un traitement de texte ou un navigateur internet. Par exemple, lorsque l'on clique sur un bouton, un vnement est lev.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

280/381

Ces vnements utilisent en gnral une construction base du dlgu EventHandler ou sa version gnrique EventHandler<>. Ce dlgu accepte deux paramtres. Le premier de type object qui reprsente la source de l'vnement, c'est--dire l'objet qui a lev l'vnement. Le second est une classe qui drive de la classe de base EventArgs. Rcrivons notre exemple avec ce nouveau handler. Nous avons donc besoin en premier lieu d'une classe qui drive de la classe EventArgs : Code : C# public class ChangementDePrixEventArgs : EventArgs { public decimal Prix { get; set; } }

Plus besoin de dclaration de dlgu, nous utilisons directement EventHandler dans notre classe Voiture : Code : C# public class Voiture { public event EventHandler<ChangementDePrixEventArgs> ChangementDePrix; public decimal Prix { get; set; } public void PromoSurLePrix() { Prix = Prix / 2; if (ChangementDePrix != null) ChangementDePrix(this, new ChangementDePrixEventArgs { Prix = Prix }); } }

Et notre dmo devient : Code : C# class Program { static void Main(string[] args) { new DemoEvenement().Demo(); } } public class DemoEvenement { public void Demo() { Voiture voiture = new Voiture { Prix = 10000 }; voiture.ChangementDePrix += voiture_ChangementDePrix; } voiture.PromoSurLePrix();

private void voiture_ChangementDePrix(object sender, ChangementDePrixEventArgs e) { Console.WriteLine("Le nouveau prix est de : " + e.Prix); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


}

281/381

Remarquons la mthode voiture_ChangementDePrix qui prend dsormais deux paramtres. Le premier reprsente l'objet Voiture, si nous en avions besoin, nous pourrions l'utiliser avec un cast adquat. Le second reprsente l'objet contenant le prix de la voiture en promotion. noter qu'en gnral, nous allons beaucoup utiliser les vnements dfinis par le framework .NET. Il est cependant assez rare davoir en dfinir un soi-mme.

En rsum
Les dlgus permettent de crer des variables pointant vers des mthodes. Les dlgus sont la base des vnements. On utilise les expressions lambdas pour simplifier l'criture des dlgus. Les vnements sont un mcanisme du C# permettant une classe d'tre notifie d'un changement.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

282/381

Grer les erreurs : les exceptions


Nous avons parl rapidement des erreurs dans nos applications C# en disant qu'il s'agissait d'exceptions. C'est le moment d'en savoir un peu plus et surtout d'apprendre les grer ! Dans ce chapitre, nous allons apprendre comment crer et intercepter une exception.

Intercepter une exception


Rappelez-vous de ce code : Code : C# string chaine = "dix"; int valeur = Convert.ToInt32(chaine);

Si nous lexcutons, nous aurons lerreur suivante :

Lapplication nous affiche un message derreur et lapplication plante lamentablement produisant un rapport derreur. Ce quil se passe en fait, cest que lors de la conversion, si le framework .NET narrive pas convertir correctement la chaine de caractres en entier, il lve une exception. Cela veut dire quil informe le programme quil rencontre un cas limite qui ncessite dtre gr. Si ce cas limite nest pas gr, alors lapplication plante et cest le CLR qui intercepte lerreur et qui fait produire un rapport au systme dexploitation.

Pourquoi une exception et pas un message derreur ?

Lintrt des exceptions est qu'elles sont types. Finis les codes derreurs incomprhensibles. Cest le type de lexception, c'est- -dire sa classe, qui va nous permettre didentifier le problme. Pour viter le plantage de lapplication, nous devons grer ces cas limites et intercepter les exceptions. Pour ce faire, il faut encadrer les instructions pouvant atteindre des cas limites avec le bloc dinstruction trycatch, par exemple : Code : C#

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


try {

283/381

} catch (Exception) { Console.WriteLine("Une erreur s'est produite dans la tentative de conversion"); }

string chaine = "dix"; int valeur = Convert.ToInt32(chaine); Console.WriteLine("Ce code ne sera jamais affich");

Si nous excutons ce bout de code, lapplication ne plantera plus et affichera quune erreur sest produite Nous avons attrap lexception leve par la mthode de conversion grce au mot-cl catch. Cette construction nous permet de surveiller lexcution dun bout de code, situ dans le bloc try et sil y a une erreur, alors nous interrompons son excution pour traiter lerreur en allant dans le bloc catch. La suite du code dans le try, savoir laffichage de la ligne avec Console.WriteLine, ne sera jamais excut car lorsque la conversion choue, il saute directement au bloc catch. Inversement, il est possible de ne jamais passer dans le bloc catch si les instructions ne provoquent pas derreur : Code : C# try {

} catch (Exception) { Console.WriteLine("Nous ne passons jamais ici ..."); }

string chaine = "10"; int valeur = Convert.ToInt32(chaine); Console.WriteLine("Conversion OK");

Ainsi le code ci-dessus affichera bien uniquement que la conversion est bonne. Et en toute logique, il ne passera pas dans le bloc de traitement derreur, car il ny en a pas eu. Il est possible dobtenir des informations sur lexception en utilisant un paramtre dans le bloc catch : Code : C# try {

} catch (Exception ex) { Console.WriteLine("Il y a un eu une erreur, plus d'informations ci-dessous :"); Console.WriteLine(); Console.WriteLine("Message d'erreur : " + ex.Message); Console.WriteLine(); Console.WriteLine("Pile d'appel : " + ex.StackTrace); Console.WriteLine(); Console.WriteLine("Type de l'exception : " + ex.GetType()); }

string chaine = "dix"; int valeur = Convert.ToInt32(chaine);

Ici, nous affichons le message derreur, la pile dappel et le type de lexception, ce qui donne :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

284/381

Dune manire gnrale, la mthode ToString() de lexception fournit des informations suffisantes pour identifier lerreur : Code : C# try {

} catch (Exception ex) { Console.WriteLine("Il y a un eu une erreur : " + ex.ToString()); }

string chaine = "dix"; int valeur = Convert.ToInt32(chaine);

Ce qui donne :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

285/381

Les exceptions peuvent tre de beaucoup de formes. Ici nous remarquons que lexception est de type System.FormatException. Cette exception est utilise en gnral lorsque le format dun paramtre ne correspond pas ce qui est attendu. En loccurrence ici nous attendons un paramtre de type chaine de caractres qui reprsente un entier. Cest une exception spcifique qui est ddie un type derreur prcis. Il faut savoir que comme beaucoup dautres objets du framework .NET, les exceptions spcifiques drivent dune classe de base, savoir la classe Exception. Il existe une hirarchie entre les exceptions. Globalement, deux grandes familles dexceptions existent : ApplicationException et SystemException. Elles drivent toutes les deux de la classe de base Exception. La premire est utilise lorsque des erreurs rcuprables sur des applications apparaissent, la seconde est utilise pour toutes les exceptions gnres par le framework .NET. Par exemple, lexception que nous avons vue, FormatException drive directement de SystemException qui drive elle-mme de la classe Exception. Le framework .NET dispose de beaucoup dexceptions correspondant beaucoup de situations. Notons encore au passage une autre exception bien connue des dveloppeurs qui est la NullReferenceException. Elle se produit lorsquon essaie daccder un objet qui vaut null. Par exemple : Code : C# Voiture voiture = null; voiture.Vitesse = 10;

V ous aurez remarqu que dans la construction suivante : Code : C# try {

} catch (Exception ex) { Console.WriteLine("Il y a un eu une erreur : " + ex.ToString()); }

string chaine = "dix"; int valeur = Convert.ToInt32(chaine);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

286/381

nous voyons que le bloc catch prend en paramtre la classe de base Exception. Cela veut dire que nous souhaitons intercepter toutes les exceptions qui drivent de Exception ; cest--dire en fait toutes les exceptions, car pour avoir une exception, elle doit forcment driver de la classe Exception. Cest utile lorsque nous voulons attraper toutes les exceptions. Mais savons-nous forcment quoi faire dans le cas de toutes les erreurs ? Il est possible dtre plus prcis afin de nattraper quun seul type dexception. Il suffit de prciser le type de lexception attendu comme paramtre du catch. Par exemple le code suivant nous permet dintercepter toutes les exceptions du type FormatException : Code : C# try {

} catch (FormatException ex) { Console.WriteLine(ex); }

string chaine = "dix"; int valeur = Convert.ToInt32(chaine);

Cela veut par contre dire que si nous avons une autre exception ce moment-l, du style NullReferenceException, lexception ne sera pas attrape. Ce qui fait que le code suivant va planter : Code : C# try {

} catch (FormatException ex) { Console.WriteLine("Erreur de format : " + ex); }

Voiture v = null; v.Vitesse = 10;

En effet, nous demandons la surveillance de lexception FormatException uniquement. Ainsi, lexception NullReferenceException ne sera pas attrape.

Intercepter plusieurs exceptions


Code : C# try {

Pour attraper les deux exceptions, il est possible denchainer les blocs catchavec des paramtres diffrents :

// code provoquant une exception } catch (FormatException ex) { Console.WriteLine("Erreur de format : " + ex); } catch (NullReferenceException ex) { Console.WriteLine("Erreur de rfrence nulle : " + ex); }

Dans ce code, cela veut dire que si le code surveill provoque une FormatException, alors nous afficherons le message

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Erreur de format . Sil provoque une NullReferenceException, alors nous afficherons le message Erreur de rfrence nulle . Notez bien que nous ne pouvons rentrer chaque fois que dans un seul bloc catch. Une autre solution serait dattraper une exception plus gnraliste par exemple SystemException dont drive FormatException et NullReferenceException : Code : C# try {

287/381

// code provoquant une exception } catch (SystemException ex) { Console.WriteLine("Erreur systme : " + ex); }

Par contre, il faut savoir que le code prcdent attrape toutes les exceptions qui drivent de SystemException. Cest le cas de FormatException et NullReferenceException, mais cest aussi le cas pour beaucoup dautres exceptions. Lorsquon surveille un bloc de code, on commence en gnral par surveiller toutes les exceptions les plus fines possibles qui nous intressent et on remonte en considrant les exceptions plus gnrales, jusqu terminer par la classe Exception : Code : C# try {

// code provoquant une exception } catch (FormatException ex) { Console.WriteLine("Erreur de format : " + ex); } catch (NullReferenceException ex) { Console.WriteLine("Erreur de rfrence nulle : " + ex); } catch (SystemException ex) { Console.WriteLine("Erreur systme autres que FormatException et NullReferenceException : " + ex); } catch(Exception ex) { Console.WriteLine("Toutes les autres exceptions : " + ex); }

chaque excution, cest le bloc catch qui se rapproche le plus de lexception leve qui est utilis. Cest un peu comme une opration conditionnelle. .NET vrifie dans un premier temps que lexception nest pas une FormatException. Si ce nest pas le cas, il vrifiera quil na pas faire une NullReferenceException. Ensuite, il vrifiera quil ne sagit pas dune SystemException. Enfin, il interceptera toutes les exceptions dans le dernier bloc de code car Exception tant la classe mre, toutes les exceptions sont interceptes avec ce type. A noter quil est possible dimbriquer les trycatch si cela savre pertinent. Par exemple : Code : C# string saisie = Console.ReadLine(); try { int entier = Convert.ToInt32(saisie);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Console.WriteLine("La saisie est un entier"); } catch (FormatException) { try { double d = Convert.ToDouble(saisie); Console.WriteLine("La saisie est un double"); } catch (FormatException) { Console.WriteLine("La saisie n'est ni un entier, ni un double"); } }

288/381

Ce code nous permet de tester si la saisie est un entier. Si une exception se produit, alors nous tentons de le convertir en double. Sil y a encore une exception, alors nous affichons un message indiquant que les deux conversions ont chou.

Le mot-cl finally
Nous avons vu que lorsquun code tait surveill dans un bloc trycatch, on sortait du bloc try si jamais une exception tait leve, pour atterrir dans le bloc catch. Cela veut dire quil est impossible de garantir quune instruction sera excute dans notre code, si jamais une exception nous fait sortir du bloc. Cest l quintervient le mot-cl finally. Il permet dindiquer que dans tous les cas, un code doit tre excut, quune exception intervienne ou pas. Par exemple : Code : C# try {

} catch (FormatException) { Console.WriteLine("Vous avez saisi autre chose qu'un entier"); } finally { Console.WriteLine("Merci d'avoir saisi quelque chose"); }

string saisie = Console.ReadLine(); int valeur = Convert.ToInt32(saisie); Console.WriteLine("Vous avez saisi un entier");

Nous demandons une saisie utilisateur. Nous tentons de convertir cette saisie en entier. Si la conversion fonctionne, nous restons dans le bloc try et nous affichons :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

289/381

Si la conversion lve une FormatException, nous affichons :

Dans les deux cas, nous passons obligatoirement dans le bloc finally pour afficher le remerciement. Le bloc finally est utile par exemple quand il sagit de librer la mmoire, denregistrer des donnes, dcrire dans un fichier de log, etc. Il est important de remarquer que peu importe la construction, le bloc finally est toujours excut. Ainsi, mme si on relve une exception dans le bloc catch : Code : C# try {

Convert.ToInt32("ppp");

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


} catch (FormatException) { throw new NotImplementedException(); } finally { Console.WriteLine("Je suis quand mme pass ici"); }

290/381

nous afficherons toujours notre message... Ou mme lorsque nous souhaitons sortir d'une mthode avec le mot-cl return : Code : C# static void Main(string[] args) { MaMethode(); } private static void MaMethode() { try { Convert.ToInt32("ppp"); } catch (FormatException) { return; } finally { Console.WriteLine("Je suis quand mme pass ici"); } }

Ici, le bloc finally est quand mme excut.

Lever une exception

Il est possible de dclencher soi-mme la leve dune exception. Cest utile si nous considrons que notre code a atteint un cas limite, quil soit fonctionnel ou technique. Pour lever une exception, nous utilisons le mot-cl throw, suivi dune instance dune exception. Imaginons par exemple une mthode permettant de calculer la racine carre dun double. Nous pouvons obtenir un cas limite lorsque nous tentons de passer un double ngatif : Code : C# public static double RacineCarree(double valeur) { if (valeur <= 0) throw new ArgumentOutOfRangeException("valeur", "Le paramtre doit tre positif"); return Math.Sqrt(valeur); }

Ici, nous instancions une ArgumentOutOfRangeException en utilisant un constructeur deux paramtres. Ceux-ci permettent dindiquer le nom du paramtre ainsi que le message derreur. Cette exception est une exception du framework .NET utilise pour indiquer quun paramtre est en dehors des plages de valeurs autorises. Cest exactement ce quil nous faut ici. Puis nous levons lexception avec le mot-cl throw.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Nous pouvons utiliser la mthode ainsi : Code : C# static void Main(string[] args) { try { double racine = RacineCarree(-5); } catch (Exception ex) { Console.WriteLine("Impossible d'effectuer le calcul : " + ex.Message); } }

291/381

Ce qui donnera :

Il aurait t possible de lever une exception plus gnrique avec la classe de base Exception : Code : C# throw new Exception("Le paramtre doit tre positif");

Mais noubliez pas que plus lexception est finement type, plus elle sera facile traiter prcisment. Cela permet dviter dattraper toutes les exceptions dans le mme catch avec la classe de base Exception. noter que lorsque notre programme rencontre le mot-cl throw, il arrte lexcution du programme pour partir dans le bloc trycatch correspond (sil existe). Cela veut dire quune mthode qui doit renvoyer un paramtre pourra compiler si son chemin se termine par une leve dexception, comme cest le cas pour le calcul de la racine carre.

Propagation de lexception
Il est important de noter que lorsquun bout de code se situe dans un bloc trycatch, tout le code qui est dessous est surveill, mme sil y a plusieurs mthodes qui sappellent les unes les autres. Par exemple, si nous appelons depuis la mthode Main() une Methode1() qui appelle une Methode2() qui appelle une Methode3() qui lve une exception, alors nous serons capable de lintercepter depuis la mthode Main() avec un

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


trycatch : Code : C# static void Main(string[] args) { try { Methode1(); } catch (NotImplementedException) { Console.WriteLine("On intercepte l'exception de la mthode 3"); } } public static void Methode1() { Methode2(); } public static void Methode2() { Methode3(); } public static void Methode3() { throw new NotImplementedException(); }

292/381

noter quune NotImplementedException est une exception utilise pour indiquer quun bout de code na pas encore t implment. Il est galement possible dattraper une exception, de la traiter et de choisir quelle continue se propager. Par exemple, imaginons que nous avons un bloc trycatch qui nous permet de surveiller tout notre programme et que nous ayons surveiller un bout de code ailleurs dans le programme qui peut produire une situation limite : Code : C# static void Main(string[] args) { try { MaMethode(); } catch (Exception ex) { // ici, on intercepte toutes les erreurs possibles en indiquant qu'un problme inattendu s'est produit Console.WriteLine("L'application a rencontr un problme, un mail a t envoy l'administrateur ..."); EnvoyerExceptionAdministrateur(ex); } } public static void MaMethode() { try { Console.WriteLine("Veuillez saisir un entier :"); string chaine = Console.ReadLine(); int entier = Convert.ToInt32(chaine); }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


catch (FormatException) { Console.WriteLine("La saisie n'est pas un entier"); } catch (Exception ex) { EnregistrerErreurDansUnFichierDeLog(ex); throw; }

293/381

Jai une saisie faire et convertir en entier. Si la conversion choue, je suis capable de lindiquer lutilisateur en surveillant la FormatException. Par contre, si une exception inattendue se produit, je souhaite pouvoir faire quelque chose, en loccurrence enregistrer lexception dans un fichier, mais comme cest un cas limite non prvu je souhaite que lexception continue se propager afin quelle soit attrape par le bloc trycatch qui permettra denvoyer un mail ladministrateur. Dans ce cas, jutilise un catch gnraliste pour traiter les exceptions inattendues afin de loguer lexception puis jutilise directement le mot-cl throw afin de permettre de relever lexception.

Crer une exception personnalise

Grce au typage fort des exceptions, il est pratique dutiliser un type dexception pour reconnaitre un cas limite, comme une erreur de conversion ou une exception de rfrence nulle. Nous allons pouvoir utiliser certaines de ces exceptions pour nos besoins, comme ce que nous avions fait avec lexception ArgumentOutOfRangeException. Bien sr, il est possible de crer nous-mmes nos exceptions afin de lever nos propres exceptions correspondant des cas limites fonctionnels ou techniques. Par exemple, imaginons un site de-commerce qui affiche une page correspondant au descriptif dun produit afin de pouvoir le commander. Nous chargeons le produit. Si le produit nest plus en stock alors il peut tre judicieux de lever une exception afin que le site puisse grer ce cas limite et afficher un message en consquence. Crons donc notre exception personnalise : ProduitNonEnStockException Pour ce faire, il suffit de crer une classe qui drive de la classe de base Exception : Code : C# public class ProduitNonEnStockException : Exception { }

Qui pourra tre utilise ainsi : Code : C# static void Main(string[] args) { try { ChargerProduit("TV HD"); } catch (ProduitNonEnStockException ex) { Console.WriteLine("Erreur : " + ex.Message); } } public static Produit ChargerProduit(string nomProduit) { Produit produit = new Produit(); // remplacer par le chargement du produit if (produit.Stock <= 0) throw new ProduitNonEnStockException(); return produit; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

294/381

Il serait intressant de pouvoir rendre lexception plus explicite en modifiant par exemple la proprit message de lexception. Pour ce faire, il suffit dutiliser la surcharge du constructeur prenant une chaine de caractres en paramtre afin de pouvoir mettre jour la proprit Message (qui est en lecture seule) : Code : C# public class ProduitNonEnStockException : Exception { public ProduitNonEnStockException() : base("Le produit n'est pas en stock") { } }

Nous pouvons galement crer un constructeur qui prend le nom du produit en paramtre afin de rendre le message encore plus prcis : Code : C# public class ProduitNonEnStockException : Exception { public ProduitNonEnStockException(string nomProduit) : base("Le produit " + nomProduit + " n'est pas en stock") { } }

Que nous pourrons utiliser ainsi : Code : C# public static Produit ChargerProduit(string nomProduit) { Produit produit = new Produit(); // remplacer par le chargement du produit if (produit.Stock <= 0) throw new ProduitNonEnStockException(nomProduit); return produit; }

Ce qui donne :

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

295/381

noter que pour construire cette exception personnalise, nous avons driv de la classe de base Exception. Il aurait pu galement tre possible de driver de la classe ApplicationException pour conserver une hirarchie cohrente dexceptions.

En rsum
Les exceptions permettent de grer les cas limites d'une mthode. On utilise le bloc trycatch pour encapsuler un bout de code surveiller. Il est possible de crer des exceptions personnalises en drivant de la classe de base Exception. On peut lever tout moment une exception grce au mot-cl throw. Les exceptions ne doivent pas servir masquer les bugs.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

296/381

TP vnements et mto
Bienvenue dans le dernier TP de cette partie. Tenez bon, aprs on change de domaine pour aborder d'autres notions. Dans ce TP, nous allons pratiquer les vnements. Le but est de savoir en crer un et de pouvoir s'y abonner pour tre notifi d'une information. V ous tes prts ? Alors c'est parti !

Instructions pour raliser le TP


Nous allons raliser ici un mini simulateur de mto qui sera utilis par un statisticien afin den faire des statistiques (logique ). Bon, cest le contexte, mais cest juste un exemple. Nesprez pas non plus raliser un vrai simulateur mto dans ce TP. Bref. Nous devons crer un simulateur de mto. Lorsque celui-ci est dmarr, il gnre autant de nombres alatoires que demand, des nombres entre 0 et 100. Si le nombre alatoire est infrieur 5, alors cela veut dire que le temps est au soleil. Sil est suprieur ou gal 5 et infrieur 50, alors nous aurons des nuages. Sil est suprieur ou gal 50 et infrieur 90, alors nous aurons de la pluie. Sinon, nous aurons de lorage. Un vnement sera lev chaque changement de temps. Le but de notre statisticien est de sabonner aux vnements du simulateur mto afin de compter le nombre de fois o il a fait soleil et le nombre de fois o le temps a chang. Il affichera ensuite son rapport en indiquant ces deux rsultats et le pourcentage de fois o il a fait soleil. (Je veux bien que ce pourcentage soit un entier). Cest tout pour lnonc. Maintenant, vous avez assez de connaissances pour que je ne dtaille pas plus. Bon courage !

Correction
Allez, cest parti pour la correction. Tout dabord, nous devons crer notre simulateur mto. Il sera reprsent par une classe : Code : C# public class SimulateurMeteo { }

Nous aurons galement besoin de quelque chose pour reprsenter le temps, soleil, nuage, pluie et orage. Une numration semble approprie : Code : C# public enum Temps { Soleil, Nuage, Pluie, Orage }

Enfin, nous aurons notre statisticien : Code : C# public class Statisticien { }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

297/381

Commenons par le simulateur de mto. Nous aurons besoin de plusieurs variables membres afin de stocker notre gnrateur de nombre alatoires, le dernier temps quil a fait et le nombre de rptitions. Le nombre de rptitions pourra tre un paramtre du constructeur : Code : C# public class SimulateurMeteo { private Temps? ancienTemps; private int nombreDeRepetitions; private Random random; public SimulateurMeteo(int nombre) { random = new Random(); ancienTemps = null; nombreDeRepetitions = nombre; }

tant donn que nous allons dterminer plusieurs nombres alatoires, il est pertinent de ne pas r-allouer chaque fois le gnrateur de nombre alatoire. Cest pour cela quon le cre une unique fois dans le constructeur de la classe. Crons dsormais une mthode permettant de dmarrer le simulateur et codons les rgles mtiers du simulateur : Code : C# public class SimulateurMeteo { //[] Code supprim pour plus de clart [] public void Demarrer() { for (int i = 0; i < nombreDeRepetitions; i++) { int valeur = random.Next(0, 100); if (valeur < 5) GererTemps(Temps.Soleil); else { if (valeur < 50) GererTemps(Temps.Nuage); else { if (valeur < 90) GererTemps(Temps.Pluie); else GererTemps(Temps.Orage); } } } }

Cest trs simple, on boucle sur le nombre de rptitions. Un nombre alatoire est dtermin chaque itration. La mthode GererTemps prend en paramtre le temps dtermin partir du nombre alatoire. Cest cette mthode GererTemps qui aura pour but de lever un vnement quand le temps change : Code : C# public class SimulateurMeteo

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


public class SimulateurMeteo { public delegate void IlFaitBeauDelegate(Temps temps); public event IlFaitBeauDelegate QuandLeTempsChange; // [] Code supprim pour plus de clart [] private void GererTemps(Temps temps) { if (ancienTemps.HasValue && ancienTemps.Value != temps && QuandLeTempsChange != null) QuandLeTempsChange(temps); ancienTemps = temps; } }

298/381

Ici, jai choisi de crer un seul vnement quand le temps change et de lui indiquer le temps quil fait en paramtres. Nous avons donc besoin dun dlgu qui prend un Temps en paramtres et qui ne renvoie rien. (Cest dailleurs souvent le cas des vnements). Puis nous avons besoin dun vnement du type du dlgu. Ensuite, si le temps a chang et que quelquun sest abonn lvnement, alors nous levons lvnement. Il ne reste plus qu remplir notre classe Statisticien. Cette classe a besoin de travailler sur une instance de la classe SimulateurMeteo, nous pouvons donc lui en passer une dans les paramtres du constructeur. Nous utiliserons galement des variables membres prives permettant de stocker ses analyses : Code : C# public class Statisticien { private SimulateurMeteo simulateurMeteo; private int nombreDeFoisOuLeTempsAChange; private int nombreDeFoisOuIlAFaitSoleil; public Statisticien(SimulateurMeteo simulateur) { simulateurMeteo = simulateur; nombreDeFoisOuLeTempsAChange = 0; nombreDeFoisOuIlAFaitSoleil = 0; } public void DemarrerAnalyse() { simulateurMeteo.QuandLeTempsChange += simulateurMeteo_QuandLeTempsChange; simulateurMeteo.Demarrer(); } public void AfficherRapport() { Console.WriteLine("Nombre de fois o le temps a chang : " + nombreDeFoisOuLeTempsAChange); Console.WriteLine("Nombre de fois o il a fait soleil : " + nombreDeFoisOuIlAFaitSoleil); Console.WriteLine("Pourcentage de beau temps : " + nombreDeFoisOuIlAFaitSoleil * 100 / nombreDeFoisOuLeTempsAChange + " %"); } private void simulateurMeteo_QuandLeTempsChange(Temps temps) { if (temps == Temps.Soleil) nombreDeFoisOuIlAFaitSoleil++; nombreDeFoisOuLeTempsAChange++; }

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet

299/381

Notons que dans la mthode DemarrerAnalyse, nous nous abonnons lvnement de changement de temps. La mthode qui est appele lors de la notification est trs simple, elle incrmente les compteurs. Enfin, laffichage du rapport est trivial. Ici, comme nous navons que des entiers, la division produira un entier galement. Il ne reste plus qu faire fonctionner nos objets : Code : C# class Program { static void Main(string[] args) { SimulateurMeteo simulateurMeteo = new SimulateurMeteo(1000); Statisticien statisticien = new Statisticien(simulateurMeteo); statisticien.DemarrerAnalyse(); statisticien.AfficherRapport(); } }

Ici, je travaille sur 1000 rptitions. Lorsque jexcute lapplication, jobtiens :

videmment, vu que nous travaillons avec des nombres alatoires, chacun aura un rsultat diffrent. Et voil, cest termin pour ce TP. Notre application est fonctionnelle Termin ? mmmhhh pas tout fait, allons un peu plus loin.

Aller plus loin


En ltat, ce code est fonctionnel. Cest parfait. Mais que se passe-t-il si nous dmarrons plusieurs fois lanalyse ? Nous pouvons essayer : Code : C# static void Main(string[] args) { SimulateurMeteo simulateurMeteo = new SimulateurMeteo(1000); Statisticien statisticien = new Statisticien(simulateurMeteo);

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


statisticien.DemarrerAnalyse(); statisticien.AfficherRapport(); statisticien.DemarrerAnalyse(); statisticien.AfficherRapport(); statisticien.DemarrerAnalyse(); statisticien.AfficherRapport();

300/381

Nous obtiendrons quelque chose du genre :

Les valeurs augmentent alors quelles ne devraient pas. Eh oui, nous ne rinitialisons pas les entiers permettant de stocker les statistiques. Ce nest pas forcment un bug ici, comme je navais rien dit dans lnonc, il peut paraitre pertinent de continuer incrmenter ces valeurs, comme a, je peux travailler sur une moyenne. Bon, disons que nous souhaitons les rinitialiser chaque fois, il suffit de remettre zro les compteurs dans la mthode : Code : C# public void DemarrerAnalyse() { nombreDeFoisOuLeTempsAChange = 0; nombreDeFoisOuIlAFaitSoleil = 0; simulateurMeteo.QuandLeTempsChange += simulateurMeteo_QuandLeTempsChange; simulateurMeteo.Demarrer(); }

Cependant, les compteurs augmentent toujours, moins vite, mais quand mme ! Je suis sr que vous lavez devin et que vous navez-vous-mme pas fait lerreur. En fait, cela vient de labonnement lvnement. Chaque fois que nous dmarrons lanalyse, nous nous rabonnons lvnement. Comme lvnement est multidiffusion, nous rajoutons en fait chaque fois un appel la mthode avec le +=. Ce qui veut dire qu la deuxime fois, nous appellerons la mthode deux fois, ce qui fera doubler les rsultats. la troisime fois, ils triplent Nous avons donc une erreur. Soit il faut sabonner une seule fois lvnement, par exemple dans le constructeur, soit nous pouvons nous dsabonner la fin de lanalyse, quand ce nest plus utile de recevoir lvnement.

www.siteduzero.com

Partie 3 : Le C#, un langage orient objet


Cest cela que je souhaite montrer. Il suffit de faire : Code : C# public void DemarrerAnalyse() { nombreDeFoisOuLeTempsAChange = 0; nombreDeFoisOuIlAFaitSoleil = 0; simulateurMeteo.QuandLeTempsChange += simulateurMeteo_QuandLeTempsChange; simulateurMeteo.Demarrer(); simulateurMeteo.QuandLeTempsChange -= simulateurMeteo_QuandLeTempsChange; }

301/381

On utilise loprateur -= pour enlever la mthode du dlgu. Dune manire gnrale, il est bienvenu de se dsabonner dun vnement lorsque lon sait quon ne va plus sen servir. Cela permet dviter dencombrer la mmoire qui ne saurait pas forcment se librer toute seule. Je nen dis pas plus car ceci est un concept avanc de gestion de mmoire. Gardez seulement lesprit que si on a lopportunit de se dsabonner dun vnement, il faut le faire. Enfin, nous pouvons simplifier notre code en ne crant pas notre dlgu. Effectivement, dans la mesure o celui-ci possde un seul paramtre, il est possible de le remplacer par le dlgu Action<T>. Il faut juste supprimer la dclaration du dlgu et remplacer la dclaration de lvnement par : Code : C# public class SimulateurMeteo { public event Action<Temps> QuandLeTempsChange; }

V pour ce TP sur les vnements. Il nous a permis de nous entrainer un peu sur les vnements et de continuer nous oil entrainer sur la modlisation dapplications en utilisant la POO. Pas trs compliqu en soit, mais on peut vite se rendre compte quune application peut fonctionner dans un cas, mais avoir un comportement inadapt dans un autre cas. Dune manire gnrale, il est important de retenir quil faut se dsabonner dun vnement quand cela est possible. Ouf, cest enfin fini pour ce chapitre. Comme vous avez pu le constater, la programmation oriente objet applique au C# est un vaste domaine. Et encore, je nai pas tout montr pour conserver une taille raisonnable. Nous avons pu voir pas mal de choses dont les concepts de la programmation oriente objet et comment les utiliser en C#. Nous avons galement vu que les gnriques taient un lment important du C#. Puis nous avons termin le chapitre en tudiant les vnements et les exceptions qui sont des lments incontournables pour raliser une vraie application. Il y a beaucoup de domaines que je nai pas trait, nhsitez pas tre curieux et aller farfouiller dans la documentation ou sur internet.

www.siteduzero.com

Partie 4 : C# avanc

302/381

Partie 4 : C# avanc
Nous allons continuer notre tutoriel en nous attaquant des notions de C# un peu plus avances. Maintenant que vous maitrisez bien tous les concepts de base et la POO, nous allons voir o tout ceci peut nous mener. Nous allons dcouvrir plusieurs choses dans cette partie avec notamment des informations sur laccs aux donnes avec LINQ. Nous verrons galement des petites choses sur le C# que nous navons pas pu traiter avant, faute de connaissances ou pour ne pas alourdir les chapitres dj volumineux. Enfin, nous finirons avec un aperu sur les tests unitaires ( venir). Cest parti .

Crer un projet bibliothques de classes


Pour l'instant, nous n'avons cr que des projets de type application console. Il existe plein d'autres modles de projet. Un des plus utiles est le projet permettant de crer des bibliothques de classes. Il s'agit d'un projet qui va permettre de contenir des classes que nous pourrons utiliser dans des applications. Exactement comme la bibliothque de classes du framework .NET qui nous permet d'utiliser la classe Math ou les exceptions, ou plein d'autres choses Ce type de projet permet donc de crer une assembly sous la forme d'un fichier avec l'extension .dll. Ces assemblys sont donc des bibliothques qui seront utilisables par n'importe quelle application utilisant un langage compatible avec le framework .NET.

Pourquoi crer une bibliothque de classes ?


Globalement pour deux raisons que nous allons dtailler : Rutilisabilit Architecture

Rutilisabilit
Comme indiqu en introduction, le projet de type bibliothque de classes permet dobtenir des assemblys avec lextension .dll. Nous pouvons y mettre tout le code C# que nous voulons, notamment des classes qui auront un intrt tre utilises plusieurs endroits ou partages par plusieurs applications. Cest le cas des assemblys du framework .NET. Elles possdent plein de code trs utile que nous aurons avantage utiliser pour crer nos applications. De la mme faon, nous allons pouvoir crer des classes qui pourront tre rutilises plusieurs endroits. Comme notre classe permettant de grer les listes chaines. Nimporte quel programme qui utilise des listes chaines aura intrt ne pas tout rinventer et simplement rutiliser ce code prt lemploi. Il suffira pour ce faire de rutiliser cette classe en rfrenant lassembly, comme nous lavons dj vu.

Architecture :
Lautre avantage dans la cration de bibliothques de classes est de pouvoir architecturer son application de manire faciliter sa mise en place, sa maintenabilit et lvolutivit du code. Larchitecture informatique cest comme larchitecture dune maison. Si nous mettons la douche au mme endroit que le compteur lectrique ou que la machine laver est juste ct de la chambre coucher, cela peut poser des problmes. De mme, que penser dun architecte sil place les toilettes ct du lit. Une maison mal architecture est une maison o il ne fait pas bon vivre. De mme quune application mal architecture est une application o il ne fait pas bon faire la maintenance applicative ! Architecturer son application est important surtout si lapplication est grosse. Par exemple, une bonne pratique dans une application informatique est la dcomposition en couches. Nous nallons pas faire ici un cours darchitecture, mais le but est de sparer les composantes de lapplication. Un grand nombre dapplications de gestions est compose dune couche de prsentation, dune couche mtier et dune couche daccs aux donnes, les couches communiquant entre-elles. Le but est de limiter les modifications dune couche lors de la modification dune autre. Si toutes les couches taient mlanges alors chaque modification impliquerait une srie de modifications en chaine. On peut faire une analogie avec un plat de lasagnes et un plat de spaghetti. Il est difficile de toucher un spaghetti sans toucher les autres. Cependant, il pourrait tre envisageable de toucher la couche du dessus du plat de lasagnes pour rajouter un peu de fromage sans perturber ce quil y a dessous. Miam. Il est donc intressant davoir une bibliothque de classes qui gre laccs aux donnes, une autre qui gre les rgles mtier et

www.siteduzero.com

Partie 4 : C# avanc
une autre qui soccupe dafficher le tout. Je marrte l sur larchitecture, vous aurez loccasion de vous y confronter bien assez tt .

303/381

Crer un projet de bibliothque de classe


Pour crer une bibliothque de classes, on utilise lassistant de cration de nouveau projet (Fichier > Nouveau > Nouveau projet), comme on la fait pour une application console sauf quici, on utilisera le modle bibliothque de classes . Ne le faisons pas encore.

Si nous faisons cela, Visual C# Express va nous crer une nouvelle solution contenant le projet de bibliothques de classes. Cest possible sauf quen gnral, on ajoute une bibliothque de classes pour quelle serve dans le cadre dune application. Cela veut dire que nous pouvons ajouter ce nouveau projet notre solution actuelle. Ainsi, celle-ci contiendra deux projets : Lapplication console, qui sera excutable par le systme dexploitation La bibliothque de classes, qui sera utilise par lapplication.

Pour ce faire, on peut faire un clic droit sur notre solution et faire Ajouter > Nouveau Projet.

www.siteduzero.com

Partie 4 : C# avanc

304/381

Ici, on choisit le projet de type bibliothque de classes, sans oublier de lui donner un nom, par exemple MaBibliotheque .

Visual C# Express nous cr notre projet et lajoute la solution, comme on peut le voir dans lexplorateur de solutions.

Il le gnre avec un fichier Class1.cs que nous pouvons supprimer. Nous pouvons voir que notre application console est en gras. Cela veut dire que cest ce projet que Visual C# Express va tenter de dmarrer lorsque nous utiliserons ctrl + F5. Si ce nest pas le cas, il peut tenter de dmarrer la bibliothque, ce qui na pas de sens vu quelle na pas de mthode Main(). Dans ce cas, vous pourrez le changer en faisant un clic droit sur le projet console et en choisissant Dfinir comme projet de dmarrage . Dans ce projet, nous pourrons dsormais crer nos classes en ajoutant des nouvelles classes au projet, comme on la dj fait avec lapplication console. Ajoutons par exemple la classe suivante : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
namespace MaBibliotheque { public class Bonjour { public void DireBonjour() { Console.WriteLine("Bonjour depuis la bibliothque MaBibliotheque"); } } }

305/381

Proprits de la bibliothque de classe


Si nous ouvrons les proprits de notre projet (bouton droit sur le projet, Proprits) :

La fentre des proprits saffiche :

www.siteduzero.com

Partie 4 : C# avanc

306/381

Nous pouvons voir diffrentes informations et notamment dans longlet Application que le projet possde un nom dassembly, qui correspond ici au nom du projet ainsi quun espace de nom par dfaut, qui correspond galement au nom du projet. Le nom de lassembly servira identifier lassembly, alors que lespace de nom par dfaut sera celui donn lorsque nous ajouterons une nouvelle classe (ou autre) notre projet. Cet espace de nom pourra tre chang, mais en gnral on garde un nom cohrent avec les arborescences de notre projet. Notons au passage quil y a une option permettant dindiquer la version du framework .NET que nous souhaitons utiliser. Ici, nous gardons la version 4.

Gnrer et utiliser une bibliothque de classe


Nous pouvons alors compiler cette bibliothque de classes, soit individuellement, soit en compilant tout le projet. Rendons nous dans le rpertoire o nous avons sauvegard notre bibliothque, nous voyons dans le rpertoire de sortie (chez moi : C:\Users\NicoPC\Documents\Visual Studio 2010\Projects\C#\MaPremiereApplication\MaBibliotheque\bin\ Release) quil y a un fichier du nom de notre projet dont lextension est .dll. Cest notre bibliothque de classes (mme sil ny a quune classe dedans !). Elle possde le mme nom que celui que nous avons vu dans les proprits du projet. Jen profite pour vous faire remarquer qu son ct, il y a galement un fichier du mme nom avec lextension .pdb. Je peux enfin vous rvler de quoi il sagit. Ce fichier contient les informations de dbogages, utiles lorsque nous dboguons notre application. Sans ce fichier, impossible de dboguer lintrieur du code de notre classe. Revenons lassembly gnre. Cest cette dll quil faudra rfrencer dans notre projet, comme nous avons vu au chapitre sur le rfrencement dassemblys. Si vous avez un doute, nhsitez pas retourner le consulter. Ainsi, nous serons en mesure dutiliser la classe de notre bibliothque. Rappelez-vous, pour rfrencer une assembly, nous faisons un clic droit sur les rfrences du projet et slectionnons Ajouter une rfrence . Nous pourrons rfrencer notre bibliothque soit en utilisant longlet Parcourir, qui va nous permettre de pointer directement le fichier dll contenant nos classes :

www.siteduzero.com

Partie 4 : C# avanc

307/381

soit en rfrenant directement le projet de bibliothque de classes qui se trouve dans notre solution en utilisant longlet Projet :

Cest ce choix qui doit tre privilgi lorsque notre solution contient les projets rfrencer. Gnralement, vos bibliothques vont voluer en mme temps que votre programme, donc il est judicieux de les avoir dans la mme solution que son application. Nous pourrons donc faire des rfrences projet. Si cependant les bibliothques sont stables et ne sont pas sujettes voluer, alors vous pourrez les rfrencer directement

www.siteduzero.com

Partie 4 : C# avanc
partir des dll, vous y gagnerez en temps de compilation. Utilisons dsormais notre classe avec le code suivant : Code : C# MaBibliotheque.Bonjour bonjour = new MaBibliotheque.Bonjour(); bonjour.DireBonjour();

308/381

V ous pouvez aussi bien sr inclure lespace de nom MaBibliotheque pour viter davoir prfixer notre classe. En gnral, lespace de nom dune bibliothque est diffrent de celui de lapplication. Notez que pour quune classe, comme la classe Bonjour, puisse tre utilise par une application rfrenant son assembly, elle doit tre dclare en public afin quelle soit visible par tout le monde.

Le mot-cl internal

Nous avons dj vu ce mot-cl lorsque nous parlions de visibilit avec notamment les autres mots-cls public, private et protected. Cest avec les assemblys que le mot-cl internal prend tout son sens. Il permet dindiquer quune classe, mthode ou proprit ne sera accessible qu lintrieur dune assembly. Cela permet par exemple quune classe soit utilisable par toutes les autres classes de cette assembly mais quelle ne puisse pas tre utilise par une application rfrenant lassembly. Par exemple crons dans notre bibliothque de classes les trois classes suivantes : Code : C# public class Client { private string login; public string Login { get { return login; } } private string motDePasse; public string MotDePasse { get { return motDePasse.Crypte(); } } public Client(string loginClient, string motDePasseClient) { login = loginClient; motDePasse = motDePasseClient; }

public static class Generateur { public static string ObtenirIdentifiantUnique() { Random r = new Random(); string chaine = string.Empty; for (int i = 0; i < 10; i++) { chaine += r.Next(0, 100); } return chaine.Crypte(); } } internal static class Encodage { internal static string Crypte(this string chaine) { return

www.siteduzero.com

Partie 4 : C# avanc
Convert.ToBase64String(Encoding.Default.GetBytes(chaine)); } internal static string Decrypte(this string chaine) { return Encoding.Default.GetString(Convert.FromBase64String(chaine)); } }

309/381

Les deux premires sont des classes publiques qui peuvent tre utilises depuis nimporte o, comme depuis notre programme principal : Code : C# class Program { static void Main(string[] args) { Client client = new Client("Nico", "12345"); Console.WriteLine(client.MotDePasse); } Console.WriteLine(Generateur.ObtenirIdentifiantUnique());

Par contre, la classe Encodage nest accessible que pour les deux autres classes, car elles sont dans la mme assembly. Cela veut dire que si nous tentons de lutiliser depuis notre mthode Main() : Code : C# static void Main(string[] args) { string chaine = "12345".Crypte(); } Encodage.Crypte("12345");

Nous aurons des erreurs de compilation. Cet exemple permet dillustrer lintrt pas toujours vident du mot-cl internal. noter quil existe enfin le mot-cl protected internal qui permet dindiquer que des lments sont accessibles un niveau internal pour les classes dune mme assembly mais protected pour les autres assemblys, ce qui permet dappliquer les principes de substitutions ou dhritage. V oil, vous avez vu comment crer une bibliothque de classes. Nhsitez pas crer ce genre de projet afin dy mettre toutes les classes qui peuvent tre utilises par plusieurs applications. Comme a, il suffit dune simple rfrence pour accder au code qui y est contenu. V ous vous en servirez galement pour mieux architecturer vos applications, le code sen trouvera plus clair et plus maintenable. La traduction en anglais de bibliothque est library , vous verrez souvent ce mot l sur internet. V ous le verrez galement mal francis avec librairie, ce qui est videmment une erreur.

En rsum
Un projet de bibliothque de classes permet de regrouper des classes pouvant tre utilises entre plusieurs applications. Les bibliothques de classes gnrent des assemblys avec l'extension .dll. Elles permettent galement de mieux architecturer un projet.

www.siteduzero.com

Partie 4 : C# avanc

310/381

www.siteduzero.com

Partie 4 : C# avanc

311/381

Plus loin avec le C# et .NET


Maintenant que nous en savons plus, nous allons pouvoir aborder quelques notions qui me paraissent importantes et que nous n'avons pas encore traites. Ce sera loccasion dapprofondir nos connaissances et de comprendre un peu mieux certains points qui auraient pu vous paratre obscurs. Nous allons voir des instructions C# supplmentaires qui vont nous permettre de complter nos connaissances en POO. Nous en profiterons galement pour dtailler comment le framework .NET gre les types en mmoire. V ous en saurez plus sur le formatage des chanes et aurez un aperu du ct obscur du framework .NET, la rflexion ! Bref, tout plein de nouvelles cordes nos arcs nous permettant d'tre de plus en plus efficace avec le C#. Ces nouveaux concepts vous serviront sans doute moins souvent, mais sont importants connatre.

Empcher une classe de pouvoir tre hrite


Parmi ces nouveaux concepts, nous allons voir comment il est possible de faire en sorte qu'une classe ne puisse pas tre hrite. Rappelez-vous, un moment jai dit quon ne pouvait pas crer une classe qui spcialise la classe String... Cest quoi ce mystre ? Nous, quand nous crons une classe, nimporte qui peut en hriter. Pourquoi pas la classe String ?

Cest parce que je vous avais cach le mot-cl sealed. Il permet dempcher la classe dtre hrite. Tout simplement. Pourquoi vouloir empcher dtendre une classe en la drivant ? Pour plusieurs raisons, mais gnralement nous allons recourir ce mot-cl lorsquune classe est trop spcifique une mthode ou une bibliothque et que lon souhaite empcher quelquun de pouvoir obtenir du code instable en tendant son fonctionnement. Cest typiquement le cas pour la classe String. Il y a beaucoup de classes dans le framework .NET qui sont marques comme sealed afin dviter que lon puisse faire nimporte quoi. Il faut par contre faire attention car lemploi de ce mot-cl restreint normment la faon dont on pourrait employer cette classe. Pour dclarer une classe sealed (scelle en franais) il suffit de prcder le mot-cl class du mot-cl sealed : Code : C# public sealed class ClasseImpossibleADeriver { }

Ainsi, toute tentative dhritage : Code : C# public class MaClasse : ClasseImpossibleADeriver { }

se soldera par une erreur de compilation dshonorante : Code : Console impossible de driver du type sealed 'MaPremiereApplication.ClasseImpossibleADeriver'

noter que le mot-cl sealed fonctionne galement pour les mthodes, dans ce cas, cela permet dempcher la substitution dune mthode. Reprenons notre exemple du chien muet :

www.siteduzero.com

Partie 4 : C# avanc
Code : C# public class Chien { public virtual void Aboyer() { Console.WriteLine("Wouf"); } } public class ChienMuet : Chien { public sealed override void Aboyer() { Console.WriteLine("..."); } }

312/381

Ici, nous marquons la mthode comme sealed, ce qui fait quune classe qui drive de ChienMuet ne sera pas capable de remplacer la mthode permettant daboyer. Le code suivant : Code : C# public class ChienAvecSyntheseVocale : ChienMuet { public override void Aboyer() { Console.WriteLine("Bwarf"); } }

entrainera lerreur de compilation : Code : Console

'MaPremiereApplication.ChienAvecSyntheseVocale.Aboyer()' : ne peut pas se substituer un

V pour ce mot-cl, utiliser en connaissance de cause. oil

Prcisions sur les types et gestion mmoire


Nous avons vu beaucoup de types diffrents au cours des chapitres prcdents. Nous avons vu les structures, les classes, les numrations, les dlgus, etc. Certains sont des types valeur et dautres des types rfrence. Et ils sont tous des objets. V un petit schma rcapitulatif des types que nous avons dj vus : oici

www.siteduzero.com

Partie 4 : C# avanc

313/381

Nous avons dit brivement quils taient grs diffremment par le framework .NET et que les variables de type valeur contenaient directement la valeur, alors que les variables de type rfrence possdent un lien vers un objet en mmoire. Ce quil se passe en fait quand nous dclarons une variable de type valeur, cest quil cre directement la valeur en mmoire dans ce quon appelle la pile . Cest une zone mmoire (limite) o il est trs rapide de mettre et de chercher des valeurs. De plus, cette mmoire na pas besoin dtre libre par le ramasse-miettes (que nous verrons un peu plus bas). Cest pour cela que pour des raisons de performances on peut tre amen choisir les types valeur. Par exemple lorsque nous faisons : Code : C# int age = 10; double pourcentage = 5.5;

il se passe ceci en mmoire :

La variable age est une adresse mmoire contenant la valeur 10. Cest la mme chose pour la variable pourcentage sauf que lemplacement mmoire est plus important car on peut stocker plus de choses dans un double que dans un int. En ce qui concerne les types valeur, lorsque nous instancions par exemple une classe, le C# instancie la variable maVoiture dans la pile et lui met dedans une rfrence vers le vrai objet qui lui est allou sur une zone mmoire de capacit plus importante,

www.siteduzero.com

Partie 4 : C# avanc

314/381

mais accs plus lent, que lon appelle le tas . Comme il est gr par le framework .NET, on lappelle le tas manag . Si nous avons le code suivant : Code : C# public class Voiture { public int Vitesse { get; set; } public string Marque { get; set; } } Voiture maVoiture = new Voiture { Vitesse = 10, Marque = "Peugeot" };

Nous aurons en mmoire :

noter que lorsquune variable sort de sa porte et quelle nest plus utilisable par qui que ce soit, alors la case mmoire sur la pile est marque comme de nouveau libre. V grosso modo comment est gre la mmoire. oil Il manque encore un lment fondamental du mcanisme de gestion mmoire : le ramasse-miettes. Nous en avons dj parl brivement, le ramasse miette sert librer la mmoire qui nest plus utilise dans le tas manag. Il y aurait de quoi crire un gros tutoriel rien que sur son fonctionnement, aussi nous allons expliquer rapidement comment il fonctionne sans trop rentrer dans les dtails. Le ramasse-miettes est souvent dnomm par sa traduction anglaise, le garbage collector.

Pourquoi librer la mmoire ? On a vu que quand une variable sort de porte, alors la case mmoire sur la pile est marque comme nouveau libre. Cest trs bien avec les types valeur qui sont uniquement sur la pile. Mais avec les types rfrence ? Que donne le code suivant lorsque nous quittons la mthode CreerVoiture ? Code : C# public class Voiture { public int Vitesse { get; set; } public string Marque { get; set; } } static void Main(string[] args) { CreerVoiture(); }

www.siteduzero.com

Partie 4 : C# avanc
public static void CreerVoiture() { Voiture maVoiture = new Voiture { Vitesse = 10, Marque = "Peugeot" }; }

315/381

Nous avons dit que la mmoire sur la pile redevenait libre. La rfrence vers lobjet est donc casse. Cependant, la mmoire sur le tas est toujours occupe.

Cela veut dire que notre objet est toujours en mmoire sauf que la variable maVoiture nexiste plus et donc, ne rfrence plus cet objet. Dans un langage comme le C++, nous aurions t obligs de vider explicitement la mmoire rfrence par la variable. En C#, pas besoin ! Cest le ramasse-miettes qui le fait pour nous. Encore un truc de fainant a. En fait, cest plutt une scurit quun truc de fainant. Cest la garantie que la mmoire utilise par les objets qui nexistent plus est vide et, du coup, redevient disponible pour de nouveaux objets. Grce au ramasse-miettes, nous vitons ce que lon appelle les fuites mmoires. Super gnial a. Mais, il passe quand ce ramasse-miettes ?

La rponse est simple : on ne sait pas quand il passe . En fait, il passe quand il a besoin de mmoire ou quand lapplication semble ne rien faire. videmment, lorsque le ramasse-miettes passe, les performances de lapplication sont un petit peu pnalises. Cest pour cela que lalgorithme de passage du ramassemiettes est optimis pour essayer de dranger le moins possible lapplication, lors des moments dinactivit par exemple. Par contre, quand il y a besoin de mmoire, il ne se pose pas la question : il passe quand mme. Il y aurait beaucoup de choses dire encore sur ce mcanisme mais arrtons-nous l. Retenons que le ramasse-miettes est un superbe outil qui nous permet de garantir lintgrit de notre mmoire et quil sefforce au mieux de nous embter le moins possible. Il est important de librer les ressources dont on n'a plus besoin quand cest possible, par exemple en se dsabonnant dun vnement ou lorsque nous avons utilis des ressources natives (ce que nous ne verrons pas dans ce tutoriel) ou lors daccs des fichiers ou des bases de donnes.

Masquer une mthode


Dans la partie prcdente sur la substitution, nous avons vu qu'on pouvait substituer une mthode grce au mot-cl override. Cette mthode devait d'ailleurs s'tre dclare comme candidate cette substitution grce au mot-cl virtual. Rappelez-vous de ce code : Code : C# public class Chien { public virtual void Aboyer() { Console.WriteLine("Wouaf !"); }

www.siteduzero.com

Partie 4 : C# avanc
} public class Caniche : Chien { public override void Aboyer() { Console.WriteLine("Wiiff"); } }

316/381

Si nous instancions des chiens et des caniches de cette faon : Code : C# static void Main(string[] args) { Chien chien = new Chien(); Caniche caniche = new Caniche(); Chien canicheTraiteCommeUnChien = new Caniche(); chien.Aboyer(); caniche.Aboyer(); canicheTraiteCommeUnChien.Aboyer();

Nous aurons : Code : Console Wouaf ! Wiiff Wiiff

En effet, le premier objet est un chien et les deux suivants sont des caniches. Grce la substitution, nous faisons aboyer notre chien, notre caniche et notre caniche qui se fait manipuler comme un chien. Il est possible de masquer des mthodes qui ne sont pas forcment marques comme virtuelles grce au mot-cl new. ce moment-l, la mthode ne se substitue pas la mthode drive mais la masque pour les types drivs. V oyons cet exemple : Code : C# public class Chien { public void Aboyer() { Console.WriteLine("Wouaf !"); } } public class Caniche : Chien { public new void Aboyer() { Console.WriteLine("Wiiff"); } }

www.siteduzero.com

Partie 4 : C# avanc

317/381

Remarquons que la mthode Aboyer() de la classe Chien nest pas marque virtual et que la mthode Aboyer de la classe Caniche est marque avec le mot-cl new. Il ne sagit pas ici de substitution. Il sagit juste de deux mthodes qui portent le mme nom, mais la mthode Aboyer() de la classe Caniche se charge de masquer la mthode Aboyer() de la classe mre. Ce qui fait que les prcdentes instanciations : Code : C# static void Main(string[] args) { Chien chien = new Chien(); Caniche caniche = new Caniche(); Chien canicheTraiteCommeUnChien = new Caniche(); chien.Aboyer(); caniche.Aboyer(); canicheTraiteCommeUnChien.Aboyer();

produiront cette fois-ci : Code : Console Wouaf ! Wiiff Wouaf !

Cest le dernier cas qui peut surprendre. Rappelez-vous, il ne sagit pas dun remplacement de mthode cette fois-ci, et donc le fait de manipuler le caniche en tant que Chien ne permet pas de remplacer le comportement de la mthode Aboyer(). Dans ce cas, on appelle bien la mthode Aboyer correspondant au type Chien, ce qui a pour effet dafficher Wouaf ! . Si nous navions pas utilis le mot-cl new, nous aurions eu le mme comportement mais le compilateur nous aurait avertis de ceci grce un avertissement : Code : Console

'MaPremiereApplication.Caniche.Aboyer()' masque le membre hrit 'MaPremiereApplication.C

Il nous prcise que nous masquons effectivement la mthode de la classe mre et que si cest fait exprs, alors il faut lindiquer grce au mot-cl new afin de lui montrer que nous savons ce que nous faisons. Notez quand mme que dans la majorit des cas, en POO, ce que vous voudrez faire cest bien substituer la mthode et non la masquer. Cest le mme principe pour les variables, il est galement possible de masquer une variable, quoiquen gnral, cela reflte plutt une erreur dans le code. Si nous faisons : Code : C# public class Chien { protected int age; } public class Caniche : Chien {

www.siteduzero.com

Partie 4 : C# avanc
private int age; public Caniche() { age = 0; } public override string ToString() { return "J'ai " + age + " ans"; }

318/381

Alors le compilateur nous indique que la variable age de la classe Caniche masque celle dont nous avons hrit de la classe Chien. Si cest intentionnel, il nous propose de la marquer avec le mot-cl new. Sinon, cela nous permet de constater que cette variable est peut-tre inutile (srement dailleurs !)

Le mot-cl yield
Nous avons vu dans le TP sur les gnriques comment crer un numrateur. Cest une tche un peu lourde qui ncessite pas mal de code. Omettons un instant que la classe String soit numrable et crons pour lexemple une classe qui permette dnumrer une chaine de caractres. Nous aurions pu faire quelque chose comme a : Code : C# public class ChaineEnumerable : IEnumerable<char> { private string chaine; public ChaineEnumerable(string valeur) { chaine = valeur; } public IEnumerator<char> GetEnumerator() { return new ChaineEnumerateur(chaine); } IEnumerator IEnumerable.GetEnumerator() { return new ChaineEnumerateur(chaine); }

public class ChaineEnumerateur : IEnumerator<char> { private string chaine; private int indice; public ChaineEnumerateur(string valeur) { indice = -1; chaine = valeur; } public char Current { get { return chaine[indice]; } } public void Dispose() { } object IEnumerator.Current {

www.siteduzero.com

Partie 4 : C# avanc
} get { return Current; }

319/381

public bool MoveNext() { indice++; return indice < chaine.Length; } public void Reset() { indice = -1; }

Nous avons une classe ChaineEnumerable qui encapsule une chaine de caractres de type string. Et une classe ChaineEnumerateur qui permet de parcourir une chaine et de renvoyer chaque itration un caractre, reprsent par le type char (qui est un alias de la structure System.Char). Rien de bien sorcier, mais un code plutt lourd. Regardons prsent le code suivant : Code : C# public class ChaineEnumerable : IEnumerable<char> { private string chaine; public ChaineEnumerable(string valeur) { chaine = valeur; } public IEnumerator<char> GetEnumerator() { for (int i = 0; i < chaine.Length; i++) { yield return chaine[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

Il fait la mme chose, mais dune manire bien simplifie. Nous remarquons lapparition du mot-cl yield. Il permet de crer facilement des numrateurs. Il permet, combin au mot-cl return, de renvoyer un lment dune collection et de passer llment suivant. Il peut tre combin au mot-cl break galement pour permettre darrter lnumration. Ce qui veut dire que nous aurions pu crire la mthode GetEnumerator() galement de cette faon : Code : C# public IEnumerator<char> GetEnumerator() { int i = 0; while (true) { if (i == chaine.Length) yield break;

www.siteduzero.com

Partie 4 : C# avanc
yield return chaine[i]; i++;

320/381

Ce qui est plus laid, je le conois

, mais qui permet dillustrer le mot-cl yield break.

Le mot-cl yield permet galement de renvoyer un IEnumerable (ou sa version gnrique), ainsi un peu btement, on pourrait faire : Code : C# static void Main(string[] args) { foreach (string prenom in ObtenirListeDePrenoms()) { Console.WriteLine(prenom); } } public static IEnumerable<string> ObtenirListeDePrenoms() { yield return "Nicolas"; yield return "Jrmie"; yield return "Delphine"; }

Cet exemple va surtout me permettre dillustrer ce quil se passe exactement grce au mode debug. Mettez un point darrt au dbut du programme et lancez-le en mode debug :

Appuyez sur F11 plusieurs fois pour rentrer dans la mthode ObtenirListeDePrenoms, nous voyons lindicateur se dplacer sur les diffrentes parties de linstruction foreach. Puis nous arrivons sur la premire instruction yield return :

www.siteduzero.com

Partie 4 : C# avanc

321/381

Appuyons nouveau sur F11 et nous pouvons constater que nous sortons de la mthode et que nous rentrons nouveau dans le corps de la boucle foreach qui va nous afficher le premier prnom. Continuons les F11 jusqu repasser sur le mot-cl in et rentrer nouveau dans la mthode ObtenirListeDePrenoms() et nous pouvons constater que nous retournons directement au deuxime mot-cl yield :

Et ainsi de suite jusqu ce quil ny ait plus rien dans la mthode ObtenirListeDePrenoms() et que du coup le foreach se termine. la premire lecture, ce nest pas vraiment ce comportement que nous aurions attendu V pour le principe du yield return. oil noter quun yield break nous aurait fait sortir directement de la boucle foreach. Le mot-cl yield participe ce quon appelle lexcution diffre. On value la mthode ObtenirListeDePrenoms() quau moment o on parcoure le rsultat avec la boucle foreach, ce qui pourrait paratre surprenant. Par exemple, si nous faisons : Code : C# public static IEnumerable<string> ObtenirListeDePrenoms() {

www.siteduzero.com

Partie 4 : C# avanc
yield return "Nicolas"; yield return "Jrmie"; yield return "Delphine";

322/381

static void Main(string[] args) { IEnumerable<string> prenoms = ObtenirListeDePrenoms(); Console.WriteLine("On fait des choses ..."); foreach (string prenom in prenoms) { Console.WriteLine(prenom); } }

Et que nous mettons un point darrt sur le Console.WriteLine et un autre point darrt dans la mthode ObtenirListeDePrenoms(), alors trangement, on va sarrter dans un premier temps sur le point darrt positionn sur la ligne o il y a le Console.WriteLine et ensuite nous passerons dans le point darrt positionn dans la mthode ObtenirListeDePrenoms(). En effet, on ne passera dans la mthode que lorsque nous itrerons explicitement sur les prnoms grce au foreach. Nous reviendrons sur cette excution diffre un peu plus loin. Cest le mot-cl yield qui fait a.

Le formatage de chaines, de dates et la culture


Code : C# int age = 30; Console.WriteLine("J'ai " + age + " ans");

Pour linstant, lorsque nous avons eu besoin de mettre en forme des chaines de caractres, nous avons utilis la mthode Console.WriteLine avec en paramtres des chaines concatnes entre elles grce loprateur +. Par exemple :

Il est important de savoir quil est possible de formater la chaine un peu plus simplement et surtout beaucoup plus efficacement. Ceci est possible grce la mthode string.Format. Le code prcdent peut par exemple tre remplac par : Code : C# int age = 30; string chaine = string.Format("J'ai {0} ans", age); Console.WriteLine(chaine);

La mthode string.Format accepte en premier paramtre un format de chaine. Ici, nous lui indiquons une chaine de caractres avec au milieu un caractre spcial : {0}. Il permet de dire : remplace-moi le {0} avec le premier paramtre qui va suivre , en loccurrence ici la variable age. Si nous avons plusieurs valeurs, il est possible dutiliser les caractres spciaux {1}, puis {2}, etc chaque nombre reprsentant lindice correspondant au paramtre. Par exemple : Code : C# double valeur1 = 10.5; double valeur2 = 4.2; string chaine = string.Format("{0} multipli par {1} s'crit \"{0} * {1}\" et donne comme rsultat : {2}", valeur1, valeur2, valeur1 * valeur2); Console.WriteLine(chaine);

Ce qui donne :

www.siteduzero.com

Partie 4 : C# avanc
Code : Console 10,5 multipli par 4,2 s'crit "10,5 * 4,2" et donne comme rsultat : 44,1

323/381

V ous avez pu remarquer quil est possible dutiliser le mme paramtre plusieurs endroits. La mthode Console.WriteLine dispose aussi de la capacit de formater des chaines de caractres. Ce qui veut dire que le code prcdent peut scrire : Code : C# double valeur1 = 10.5; double valeur2 = 4.2; Console.WriteLine("{0} multipli par {1} s'crit \"{0} * {1}\" et donne comme rsultat : {2}", valeur1, valeur2, valeur1 * valeur2);

Ce qui revient absolument au mme. Parlons culture dsormais. Nayez pas peur, rien voir avec des questions pour des champions, la culture en informatique correspond tout ce qui a trait aux diffrences entre les langues et les paramtres locaux. Par exemple, en France nous n'crivons pas les dates de la mme faon quaux tats-Unis. En France, nous cririons le jour de Nol 2011 de cette faon : Citation : En France Le 25/12/2011

Alors quaux tats-Unis, ils lcriraient : Citation : Aux tats-Unis The 12/25/2011

En inversant donc le mois et le jour. De la mme faon, il existe des diffrences lorsque nous crivons les nombres virgule. En France, nous cririons : Citation : En France 123,45

Alors quaux tats-Unis, ils lcriraient : Citation : Aux tats-Unis 123.45

Un point la place dune virgule, subtile diffrence. On a donc souvent des diffrences entre les langues. Et mme plus, on peut avoir des diffrences entre les langues en fonction de lendroit o elles sont parles. Citons par exemple le franais de France et le franais du Canada. Il existe donc au sein du systme dexploitation tout une liste de rgions reprsentes par un couple de lettres. Par exemple, le franais est reprsent par les lettres fr. Et mme plus prcisment, le franais de France est reprsent par fr-FR alors que celui du Canada est reprsent par fr-CA. Cest ce que lon retrouve dans les paramtres de notre systme dexploitation lorsquon va (sous Windows 7) dans le panneau de configuration, Horloge langue et rgion :

www.siteduzero.com

Partie 4 : C# avanc

324/381

Puis Modifier le format de la date, de lheure ou des nombres .

www.siteduzero.com

Partie 4 : C# avanc

325/381

Nous pouvons adapter le format celui que nous prfrons :

www.siteduzero.com

Partie 4 : C# avanc

326/381

Bref, ce choix, nous le retrouvons dans notre application si nous rcuprons la culture courante : Code : C# Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture);

Avec ceci, nous aurons : Code : Console fr-FR

Ce qui est intressant, cest que le formatage des chiffres ou des dates change en fonction de la culture. Ainsi, si nous utilisons le franais de France, pour le code suivant : Code : C# public static void Main(string[] args) {

www.siteduzero.com

Partie 4 : C# avanc
} Affiche();

327/381

public static void Affiche() { Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture); decimal dec = 5.5M; double dou = 4.8; DateTime date = new DateTime(2011, 12, 25); Console.WriteLine("Dcimal : {0}", dec); Console.WriteLine("Double : {0}", dou); Console.WriteLine("Date : {0}", date); }

nous aurons : Code : Console fr-FR Dcimal : 5,5 Double : 4,8 Date : 25/12/2011 00:00:00

Il est possible de changer la culture courante de notre application, si par exemple nous souhaitons quelle soit multiculture, en utilisant le code suivant : Code : C# System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");

Ici par exemple, jindique mon application que je souhaite travailler avec la culture des tats-Unis. Ainsi, le code prcdent, en changeant juste la culture : Code : C# public static void Main(string[] args) { System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); Affiche(); } public static void Affiche() { Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentCulture); decimal dec = 5.5M; double dou = 4.8; DateTime date = new DateTime(2011, 12, 25); Console.WriteLine("Dcimal : {0}", dec); Console.WriteLine("Double : {0}", dou); Console.WriteLine("Date : {0}", date); }

produira un rsultat lgrement diffrent :

www.siteduzero.com

Partie 4 : C# avanc
Code : Console en-US Dcimal : 5.5 Double : 4.8 Date : 12/25/2011 12:00:00 AM

328/381

Il sagit exactement de la mme information, mais formate diffremment. noter quil existe encore une autre information de culture, savoir la langue du systme dexploitation que lon retrouve dans la culture de linterface graphique, dans la proprit : Code : C# Console.WriteLine(System.Threading.Thread.CurrentThread.CurrentUICulture);

Il sagit ici de la CurrentUICulture, ne pas confondre avec la CurrentCulture. Correspondant la langue du systme dexploitation, nous nous en servirons plus volontiers pour rendre une application multi-langue. Pour finir sur le formatage des chaines, il est possible dutiliser des caractres spciaux enrichis pour changer le formatage des types numriques ou de la date. Par exemple, il est possible dafficher la date sous une forme diffrente avec : Code : C# DateTime date = new DateTime(2011, 12, 25); Console.WriteLine("La date est {0}", date.ToString("dd-MM-yyyy"));

Ici, dd sert afficher le jour, MM le mois et yyyy lanne sur quatre chiffre, ce qui donne : Code : Console La date est 25-12-2011

Il y a beaucoup doptions diffrentes que vous pouvez retrouver dans la documentation. Cela fonctionne dans le mme genre pour les numriques, qui nous permettent par exemple dafficher le nombre de diffrentes faons. Ici par exemple, jutilise la notation scientifique : Code : C# double valeur = 123.45; Console.WriteLine("Format scientifique : {0:e}", valeur);

Ce qui donne : Code : Console Format scientifique : 1,234500e+002

www.siteduzero.com

Partie 4 : C# avanc

329/381

Pour les nombres, il existe diffrents formatages que lon peut retrouver dans le tableau ci-dessous : Format {0:c} {0:d} {0:e} {0:f} {0:g} {0:n} {0:r} {0:x} Description Monnaie Dcimal Notation scientifique Virgule flottante Gnral Nombre avec formatage pour les milliers Aller-retour Hxadcimal Permet de garantir que la valeur numrique convertie en chaine pourra tre convertie nouveau en valeur numrique identique Ne fonctionne quavec les types sans virgules Valeur par dfaut Remarque Attention, la console affiche mal le caractre Ne fonctionne quavec les types sans virgules

noter que lon peut galement avoir du formatage grce la mthode ToString(). Il suffit de passer le format en paramtres, comme ici o cela me permet dafficher uniquement le nombre de chiffres aprs la virgule qui mintressent ou des chiffres significatifs : Code : C# double valeur = 10.0 / 3; Console.WriteLine("Avec 3 chiffres significatifs et 3 chiffres aprs la virgule : {0}", valeur.ToString("000.###"));

Qui donne : Code : Console Avec 3 chiffres significatifs et 3 chiffres aprs la virgule : 003,333

Mettre le format dans la mthode ToString() fonctionne aussi pour la date : Code : C# DateTime date = new DateTime(2011, 12, 25); Console.WriteLine(date.ToString("MMMM"));

Ici, je naffiche que le nom du mois : Code : Console dcembre

V pour le formatage des chaines de caractres. oil

www.siteduzero.com

Partie 4 : C# avanc

330/381

Lister tous les formatages possibles serait une tche bien ennuyeuse. V ous aurez loccasion de rencontrer dautres formatages qui permettent de faire un peu tout et nimporte quoi. V ous pourrez retrouver la plupart des formatages partir de ce lien.

Les attributs
Dans la liste des choses qui vont vous servir, on peut rajouter les attributs. Ils sont utiliss pour fournir des informations complmentaires sur une mthode, une classe, variables, etc. Ils vont nous servir rgulirement dans le framework .NET et nous aurons mme la possibilit de crer nos propres attributs. Un attribut est dclar entre crochets avec le nom de sa classe. Il peut se mettre au-dessus dune classe, dune mthode, dune proprit, etc. Par exemple, dans le code ci-dessous, je positionne lattribut Obsolete au-dessus de la dclaration dune mthode : Code : C# [Obsolete("Utilisez plutt la mthode ToString() pour avoir une reprsentation de l'objet")] public void Affiche() { // ... }

Ici, jutilise un attribut existant du framework .NET, lattribut Obsolete qui permet dindiquer quune mthode est obsolte et quil ne vaudrait mieux pas lutiliser. En gnral, il est possible de fournir une information permettant de dire pourquoi la mthode est obsolte et par quoi il faut la remplacer. Ainsi, si nous tentons dutiliser cette mthode : Code : C# public class Program { static void Main(string[] args) { new Program().Affiche(); } [Obsolete("Utilisez plutt la mthode ToString() pour avoir une reprsentation de l'objet")] public void Affiche() { // ... } }

Le compilateur nous affichera lavertissement suivant : Code : Console

'MaPremiereApplication.Program.Affiche()' est obsolte : 'Utilisez plutt la mthode ToSt

Cet attribut est un exemple, il en existe beaucoup dans le framework .NET et vous aurez loccasion den voir dautres dans les chapitres suivants. Remarquons que la classe sappelle ObsoleteAttribute et peut sutiliser soit suffixe par Attribute, soit sans, et dans ce cas, ce suffixe est ajout automatiquement. Grce lhritage, nous allons nous aussi pouvoir dfinir nos propres attributs. Il suffit pour cela de driver de la classe de base Attribute. Par exemple, dans sa forme la plus simple :

www.siteduzero.com

Partie 4 : C# avanc
Code : C# public class DescriptionClasseAttribute : Attribute { }

331/381

Nous pourrons alors utiliser notre attribut sur une classe : Code : C# [DescriptionClasse] public class Chien { }

Super, mme si a ne nous sert encore rien

Problme, jai appel mon attribut DescriptionClasse et je peux quand mme lutiliser sur une mthode : Code : C# [DescriptionClasse] public class Chien { [DescriptionClasse] public void Aboyer() { } }

Heureusement, il est possible dindiquer des restrictions sur les attributs en indiquant par exemple quil nest valable que pour les classes. Cela se fait avec un attribut : Code : C# [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class DescriptionClasseAttribute : Attribute { }

Ici par exemple, jindique que mon attribut nest valable que sur les classes et quil est possible de le mettre plusieurs fois sur la classe. Le code prcdent o lattribut est positionn sur une mthode ne compilera donc plus, avec lerreur de compilation suivante : Code : Console

L'attribut 'DescriptionClasse' n'est pas valide dans ce type de dclaration. Il n'est val

Ce qui nous convient parfaitement.

www.siteduzero.com

Partie 4 : C# avanc
Il existe dautres attributs qui permettent par exemple de nautoriser des attributs que sur les mthodes.

332/381

Il est intressant de pouvoir fournir des informations complmentaires notre attribut. Pour cela, on peut rajouter des proprits, ou avoir une surcharge complmentaire du constructeur, comme on la fait pour le message de lattribut Obsolete : Code : C# [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class DescriptionClasseAttribute : Attribute { public string Description { get; set; } public DescriptionClasseAttribute() { } public DescriptionClasseAttribute(string description) { Description = description; }

Ce qui nous permettra dutiliser notre attribut de ces deux faons : Code : C# [DescriptionClasse(Description = "Cette classe correspond un chien")] [DescriptionClasse("Elle drive de la classe Animal")] public class Chien : Animal { }

Cest trs bien ces attributs, mais nous ne sommes pas encore capables de les exploiter. V oyons comment le faire.

La rflexion
La rflexion en C# ne donne pas mal la tte, quoique Cest une faon de faire de lintrospection sur nos types de manire obtenir des informations sur eux, c'est--dire sur les mthodes, les proprits, etc. La rflexion permet galement de charger dynamiquement des types et de faire de lintrospection sur les assemblys. Cest un mcanisme assez complexe et plutt couteux en termes de temps. Le point de dpart est la classe Type qui permet de dcrire nimporte quel type. Le type dune classe peut tre obtenu grce au mot-cl typeof : Code : C# Type type = typeof(string);

Cet objet Type nous permet dobtenir plein dinformations sur nos classes au moment de lexcution. Par exemple si le type est une classe, cest--dire ni un type valeur, ni une interface, alors le code suivant : Code : C# Type type = typeof(string); Console.WriteLine(type.IsClass);

www.siteduzero.com

Partie 4 : C# avanc

333/381

nous renverra true. En effet, la proprit IsClass permet dindiquer si le type est une classe. Nous pouvons aussi obtenir le nom de mthodes grce la mthode GetMethods() : Code : C# Type type = typeof(string); foreach (MethodInfo infos in type.GetMethods()) { Console.WriteLine(infos.Name); }

Qui nous donne :

Pas trs exploitable comme rsultat, mais bon cest pour lexemple. Il y a encore pleins dinfos dans cet objet Type, qui permettent dobtenir ce que nous voulons. Cela est possible grce aux mtadonnes qui sont des informations de descriptions des types. V ous me voyez venir eh oui, nous allons pouvoir obtenir nos attributs ! Pour connaitre la liste des attributs dun type, on peut utiliser la mthode statique Attribute.GetCustomAttributes(), en lui passant en paramtre le System.Type qui est hrit de la classe abstraite MemberInfo. Si lon souhaite rcuprer un attribut particulier, on peut le passer en paramtre de la mthode : Code : C# Attribute[] lesAttributs = Attribute.GetCustomAttributes(type, typeof(DescriptionClasseAttribute));

Ceci va nous permettre de rcuprer les attributs de notre classe et en loccurrence, dobtenir leurs description. Cest ce que permet le code suivant : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
public class Program { static void Main(string[] args) { new DemoAttributs().Demo(); } } public class DemoAttributs { public void Demo() { Animal animal = new Animal(); Chien chien = new Chien(); VoirDescription(animal); VoirDescription(chien);

334/381

public void VoirDescription<T>(T obj) { Type type = typeof(T); if (!type.IsClass) return; Attribute[] lesAttributs = Attribute.GetCustomAttributes(type, typeof(DescriptionClasseAttribute)); if (lesAttributs.Length == 0) Console.WriteLine("Pas de description pour la classe " + type.Name + "\n"); else { Console.WriteLine("Description pour la classe " + type.Name); foreach (DescriptionClasseAttribute attribut in lesAttributs) { Console.WriteLine("\t" + attribut.Description); } } } }

Nous commenons par instancier un objet animal et un objet chien. Puis nous demandons leurs descriptions. La mthode gnrique VoirDescription() soccupe dans un premier temps dobtenir le type de la classe grce typeof. On soctroie une vrification permettant de nous assurer que le type est bien une classe. Ceci permet dviter daller plus loin car de toute faon, notre attribut ne sapplique quaux classes. Puis nous utilisons la mthode GetCustomAttributes pour obtenir les attributs de type DescriptionClasseAttribute. Et sil y en a, alors on les affiche. Ce qui donne : Code : Console Pas de description pour la classe Animal Description pour la classe Chien Elle drive de la classe Animal Cette classe correspond un chien

V pour les attributs, vous aurez loccasion de rencontrer des attributs du framework .NET un peu plus loin dans ce tutoriel, oil mais globalement, il est assez rare davoir crer soi-mme ses attributs.

www.siteduzero.com

Partie 4 : C# avanc

335/381

En ce qui concerne la rflexion, il faut bien comprendre que le sujet est beaucoup plus vaste que a. Nous avons cependant vu ici un aperu de ce que permet de faire la rflexion, en illustrant le mcanisme dintrospection sur les attributs.

En rsum
Il est possible d'empcher une classe d'tre drive grce au mot-cl sealed. Le garbage collector est le mcanisme permettant de librer la mmoire alloue sur le tas manag qui n'est plus rfrence dans une application. Le mot-cl yield permet de crer des numrateurs facilement et participe au mcanisme d'excution diffre. Le framework .NET gre les diffrents formats des chanes grce la culture de l'application. La rflexion est un mcanisme d'introspection sur les types permettant d'obtenir des informations sur ces derniers lors de l'excution.

www.siteduzero.com

Partie 4 : C# avanc

336/381

La configuration d'une application


Dans le cycle de vie d'une application, il est frquent que de petites choses changent. Imaginons que mon application doive se connecter un serveur FTP pour sauvegarder les donnes sur lesquelles j'ai travaill. Pendant mes tests, effecuts en local, mon serveur FTP pourrait avoir l'adresse ftp://localhost avec un login et un mot de passe test. videmment, lors de l'utilisation relle de mon application, l'adresse changera, et le login et le mot de passe varieront en fonction de l'utilisateur. Il faut tre capable de changer facilement ces paramtres sans avoir modifier le code ni recompiler l'application. C'est l qu'interviennent les fichiers de configuration : ils permettent de stocker toutes ces petites choses qui servent faire varier notre application. Pour les clients lourds, comme nos applications console, il sagit du fichier app.config : un fichier XML qui contient la configuration de notre application. Il stocke des chanes de connexion une base de donnes, une url de service web, des prfrences utilisateurs, etc. Bref, tout ce qui va permettre de configurer notre application !

Rappel sur les fichiers XML


V ous ne connaissez pas les fichiers XML ? Si vous voulez en savoir plus, nhsitez pas faire un petit tour sur internet, cest un format trs utilis dans linformatique. Pour faire court, le fichier XML est un langage de balise, un peu comme le HTML, o lon dcrit de linformation. Les balises sont des valeurs entoures de < et > qui dcrivent la smantique de la donne. Par exemple : Code : XML <prenom>Nicolas</prenom>

La balise <prenom> est ce quon appelle une balise ouvrante, cela signifie que ce qui se trouve aprs (en loccurrence la chaine Nicolas ) fait partie de cette balise jusqu ce que lon rencontre la balise fermante </prenom> qui est comme la balise ouvrante lexception du / prcdant le nom de la balise. Le XML est un fichier facile lire par nous autres humains. On en dduit assez facilement que le fichier contient la chaine Nicolas et quil sagit smantiquement dun prnom. Une balise peut contenir des attributs permettant de donner des informations sur la donne. Les attributs sont entours de guillemets " et " et font partis de la balise. Par exemple : Code : XML <client nom="Nicolas" age="30"></client>

Ici, la balise client possde un attribut nom ayant la valeur Nicolas et un attribut age ayant la valeur 30 . Encore une fois, cest trs facile lire pour un humain. Il est possible que la balise nait pas de valeur, comme cest le cas dans lexemple ci-dessus. On peut dans ce cas-l remplacer la balise ouvrante et la balise fermante par cet quivalent : Code : XML <client nom="Nicolas" age="30"/>

Enfin, et nous allons terminer notre aperu rapide du XML avec un dernier point. Il est important de noter que le XML peut imbriquer ses balises et quil ne peut possder quun seul lment racine, ce qui nous permet davoir une hirarchie de donnes. Par exemple nous pourrons avoir : Code : XML <listesDesClient> <client type="Particulier"> <nom>Nicolas</nom> <age>30</age> </client> <client type="Professionel"> <nom>Jrmie</nom>

www.siteduzero.com

Partie 4 : C# avanc
<age>40</age> </client> </listesDesClient>

337/381

On voit tout de suite que le fichier dcrit une liste de deux clients. Nous en avons un qui est un particulier, qui sappelle Nicolas et qui a 30 ans alors que lautre est un professionnel, prnomm Jrmie et qui a 40 ans.

Crer le fichier de configuration


Pourquoi utiliser un fichier de configuration ? pour viter de mettre des valeurs en dur dans le code. Imaginons que nous utilisions une url de service web dans notre application, si l'url change, on aimerait ne pas avoir recompiler le code. pour viter d'utiliser la base de registre comme cela a beaucoup t fait dans les premires versions de Windows et de donner les droits de modification de base de registre.

Ces fichiers permettent davoir des informations de configuration, potentiellement types. De plus, le framework .NET dispose de mthodes pour y accder facilement. L'intrt d'utiliser un fichier XML plutt qu'un fichier binaire est que ce fichier est lisible et comprhensible facilement. On peut galement le modifier la main sans un systme volu permettant de faire des modifications. V plein de raisons pour lesquelles on va utiliser ces fichiers. oil Pour ajouter un fichier de configuration : faisons un clic droit sur le projet Ajouter > Nouvel lment

Et choisissons le modle de fichier Fichier de configuration de lapplication :

www.siteduzero.com

Partie 4 : C# avanc

338/381

Gardez lui son nom et validez sa cration. Ce fichier est presque vide : Code : XML <?xml version="1.0" encoding="utf-8" ?> <configuration> </configuration>

Il possde sur sa premire ligne un marqueur permettant didentifier le fichier comme tant un fichier XML et une balise ouvrante configuration, suivie de sa balise fermante. Cest la structure de base du fichier de configuration. Nous mettrons nos sections de configuration lintrieur de cette balise. Nous retrouvons notre fichier de configuration dans notre projet et nous pouvons le voir dans lexplorateur de documents :

Compilons notre application et rendons-nous dans le rpertoire o le fichier excutable est gnr. Nous y trouvons galement un fichier qui porte le mme nom que notre excutable et dont lextension est .exe.config. Cest bien notre fichier de configuration. Visual C# Express le dploie au mme endroit que notre application et lui donne un nom qui va lui permettre dtre exploit par notre application. Pour tre utilisables, ces fichiers doivent se situer dans le mme rpertoire que l'excutable.

www.siteduzero.com

Partie 4 : C# avanc

339/381

Lecture simple dans la section de configuration prdfinie : AppSettings


Avoir un fichier de configuration, cest bien. Mais il faut savoir lire lintrieur si nous souhaitons pouvoir lexploiter. Il existe plusieurs faons dindiquer des valeurs de configuration, nous les dcouvrirons tout au long de ce chapitre. La plus simple est dutiliser la section AppSettings . C'est une section o on peut mettre, comme son nom le suggre aux anglophones, les proprits de l'application. Pour cela, on utilisera un systme de cl / valeur pour stocker les informations. Par exemple, modifiez le fichier de configuration pour avoir : Code : XML <configuration> <appSettings> <add key="prenom" value="nicolas"/> <add key="age" value="30"/> </appSettings> </configuration>

En voyant ce fichier de configuration, ltre humain comprend assez facilement que nous allons avoir deux paramtres de configuration. Un premier qui est le prnom et qui va valoir Nicolas. Un deuxime qui est lge et qui sera de 30. Le savoir en tant qutre humain, cest bien. Pouvoir y accder dans notre programme informatique, cest encore mieux. V oyons comment faire. La premire chose faire est de rfrencer, si ce nest dj fait, lassembly qui contient toutes les classes permettant de grer la configuration. Elle sappelle (sans surprise) System.Configuration :

Pour accder au fichier de configuration, nous allons utiliser la classe statique ConfigurationManager. Pour accder aux informations contenues dans la section AppSettings, nous utiliserons sa proprit AppSettings. Et nous pourrons accder aux lments de la configuration en utilisant loprateur dindexation : []. Ce qui donne : Code : C# string prenom = ConfigurationManager.AppSettings["prenom"]; string age = ConfigurationManager.AppSettings["age"];

www.siteduzero.com

Partie 4 : C# avanc
Console.WriteLine("Prnom : " + prenom + " / Age : " + age);

340/381

On peut galement utiliser des index numriques pour y accder, mais je trouve que cela manque vraiment de clart : Code : C# string prenom = ConfigurationManager.AppSettings[0]; string age = ConfigurationManager.AppSettings[1]; Console.WriteLine("Prnom : " + prenom + " / Age : " + age);

De plus, cela oblige connatre lordre dans lequel les cls ont t mises dans le fichier. Il est possible aussi de boucler sur toutes les valeurs contenues dans la section : Code : C# foreach (string cle in ConfigurationManager.AppSettings) { Console.WriteLine("Cl : " + cle + " / Valeur : " + ConfigurationManager.AppSettings[cle]); }

La proprit AppSettings est en fait du type NameValueCollection. Il s'agit d'une collection d'lments de type chaine de caractres qui sont accessibles partir d'une cl de type chaine de caractres galement. Une valeur est donc associe une cl. noter que la casse de la cl nest pas importante pour accder la valeur associe la cl. Le code suivant : Code : C# string prenom = ConfigurationManager.AppSettings["PRENOM"];

renverra bien notre valeur de configuration. Cependant, si la valeur nexiste pas, nous obtiendrons la valeur null dans la chaine de caractres. Il est important de remarquer que nous rcuprons des chaines et que nous aurons besoin potentiellement de faire une conversion pour manipuler lge en tant quentier. Rien ne vous empche dcrire une petite mthode dextension maintenant que vous savez faire : Code : C# public static class ConfigurationManagerExtensions { public static int ObtenirValeurEntiere(this NameValueCollection appSettings, string cle) { string valeur = appSettings[cle]; return Convert.ToInt32(valeur); } }

Que nous pourrons utiliser avec : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
int age = ConfigurationManager.AppSettings.ObtenirValeurEntiere("age");

341/381

Lecture des chaines de connexion la base de donnes


Les chaines de connexion reprsentent un type de configuration particulier. Elles vont servir pour les applications ayant besoin de se connecter une base de donnes. On va y stocker tout ce dont on a besoin, comme le nom du serveur ou les identifiants pour sy connecter Nous y reviendrons plus en dtail plus tard, mais regardons la configuration suivante : Code : XML <configuration> <connectionStrings> <add name="MaConnection" providerName="System.Data.SqlClient" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=Base1; Integrated Security=true"/> <add name="MaConnection2" providerName="System.Data.SqlClient" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=Base2; Integrated Security=true"/> </connectionStrings> </configuration>

Nous dfinissons ici deux chaines de connexion qui permettent de se connecter en authentification Windows (Integrated Security=true) sur un serveur hberg en local (.\SQLEXPRESS) dont le nom est SQLEXPRESS, qui utilisent SQL SERVER (providerName="System.Data.SqlClient), qui pointent sur les bases de donnes Base1 et Base2, identifies chacune par les noms MaConnection et MaConnection2. Pour obtenir les informations de configuration individuellement, il faudra utiliser la proprit ConnectionStrings de la classe ConfigurationManager en y accdant par leurs noms : Code : C# ConnectionStringSettings chaineConnexion = ConfigurationManager.ConnectionStrings["MaConnection"]; Console.WriteLine(chaineConnexion.Name); Console.WriteLine(chaineConnexion.ConnectionString); Console.WriteLine(chaineConnexion.ProviderName);

Nous pourrons toutes les obtenir avec une boucle foreach : Code : C# foreach (ConnectionStringSettings valeur in ConfigurationManager.ConnectionStrings) { Console.WriteLine(valeur.ConnectionString); }

Nous utiliserons les chaines de connexion dans le chapitre sur laccs aux donnes.

Crer sa propre section de configuration partir dun type prdfini


Il est possible de crer sa propre section de configuration partir d'un type prdfini. Par exemple pour crer une section du mme genre que la section appSettings, qui utilise une paire cl/valeur, on peut utiliser un DictionarySectionHandler. Il existe plusieurs types prdfinis, que nous allons tudier ci-dessous.

DictionarySectionhandler

www.siteduzero.com

Partie 4 : C# avanc

342/381

DictionarySectionhandler est une classe qui fournit les informations de configuration des paires cl / valeur d'une section de configuration. Oui mais si tu nous dis que cest un systme de cl / valeur, cest comme pour les AppSettings que nous avons vus. Pourquoi utiliser une section particulire DictionarySectionhandler alors ?

Le but de pouvoir faire des sections particulires est d'organiser smantiquement son fichier de configuration, pour dcouper logiquement son fichier au lieu d'avoir tout dans la mme section. Regardons cette configuration : Code : XML <configuration> <configSections> <section name="InformationsUtilisateur" type="System.Configuration.DictionarySectionHandler" /> </configSections> <InformationsUtilisateur> <add key="login" value="nico" /> <add key="motdepasse" value="12345" /> <add key="age" value="30" /> </InformationsUtilisateur> </configuration>

La premire chose voir est que nous indiquons notre application que nous dfinissons une section de configuration du type DictionarySectionHandler et qui va sappeler InformationsUtilisateur. Cela permet ensuite de dfinir notre propre section InformationsUtilisateur, qui ressemble beaucoup la section AppSettings sauf quici, on se rend tout de suite compte quil sagit dinformations utilisateur. Pour accder notre section depuis notre programme, nous devrons utiliser le code suivant : Code : C# Hashtable section = (Hashtable)ConfigurationManager.GetSection("InformationsUtilisateur");

On utilise la mthode GetSection de la classe ConfigurationManager pour obtenir la section dont nous passons le nom en paramtre. On reoit en retour une table de hachage (HashTable) et nous pourrons lutiliser de cette faon pour obtenir les valeurs de nos cls : Code : C# Console.WriteLine(section["login"]); Console.WriteLine(section["MOTDEPASSE"]); Console.WriteLine(section["age"]);

Nous pouvons boucler sur les valeurs de la section en utilisant le code suivant : Code : C# foreach (DictionaryEntry d in section) { Console.WriteLine("Cl : " + d.Key + " / Valeur : " + d.Value); }

www.siteduzero.com

Partie 4 : C# avanc

343/381

NameValueSectionHandler
La section de type NameValueSectionHandler ressemble beaucoup la section prcdente. Observons la configuration suivante : Code : XML <configuration> <configSections> <section name="InformationsUtilisateur" type="System.Configuration.NameValueSectionHandler" /> </configSections> <InformationsUtilisateur> <add key="login" value="nico" /> <add key="motdepasse" value="12345" /> <add key="age" value="30" /> </InformationsUtilisateur> </configuration>

Cest la mme que juste prcdemment, lexception du type de la section, qui cette fois-ci est NameValueSectionHandler. Ce qui implique que nous obtenons un type diffrent en retour de lappel la mthode GetSection, savoir un NameValueCollection : Code : C# NameValueCollection section = (NameValueCollection)ConfigurationManager.GetSection("InformationsUtilisateur");

La rcupration des informations de configuration se fait de la mme faon : Code : C# Console.WriteLine(section["login"]); Console.WriteLine(section["MOTDEPASSE"]); Console.WriteLine(section["age"]);

Ou encore avec une boucle pour toutes les rcuprer : Code : C# foreach (string cle in section) { Console.WriteLine("Cl : " + cle + " / Valeur : " + section[cle]); }

vous de voir lequel des deux vous prfrez, mais dans tous les cas, il faudra fonctionner avec un systme de cl valeur.

SingleTagSectionHandler

www.siteduzero.com

Partie 4 : C# avanc

344/381

Ce troisime type permet de grer une section diffrente des deux prcdentes. Il sera possible davoir autant dattributs que lon souhaite dans la section. Prenez par exemple cet exemple de configuration : Code : XML <configuration> <configSections> <section name="MonUtilisateur" type="System.Configuration.SingleTagSectionHandler" /> </configSections> <MonUtilisateur prenom="Nico" age="30" adresse="9 rue des bois"/> </configuration>

Nous voyons que je peux mettre autant dattributs que je le souhaite. Par contre, il ne sera possible de faire apparaitre la section MonUtilisateur quune seule fois, alors que dans les sections prcdentes, nous avions une liste de cl / valeur. Nous pourrons rcuprer notre configuration avec le code suivant : Code : C# Hashtable section = (Hashtable)ConfigurationManager.GetSection("MonUtilisateur"); Console.WriteLine(section["prenom"]); Console.WriteLine(section["age"]); Console.WriteLine(section["adresse"]);

Attention par contre, cette fois-ci la casse est importante pour obtenir la valeur de notre attribut. Notons notre boucle habituelle permettant de retrouver tous les attributs de notre section : Code : C# foreach (DictionaryEntry d in section) { Console.WriteLine("Attribut : " + d.Key + " / Valeur : " + d.Value); }

V pour les sections utilisant un type prdfini. oil

Les groupes de sections


Super, nous savons dfinir des sections de configuration. Elles nous permettent dorganiser un peu mieux notre fichier de configuration. Par contre, si les sections se multiplient, cela va nouveau tre le bazar. Heureusement, les groupes de sections sont l pour remettre de lordre. Comme son nom lindique, un groupe de section va permettre de regrouper plusieurs sections. Le but est de clarifier le fichier de configuration. Regardons lexemple suivant : Code : XML <configuration> <configSections> <sectionGroup name="Utilisateur"> <section name="ParametreConnexion" type="System.Configuration.SingleTagSectionHandler" /> <section name="InfoPersos" type="System.Configuration.DictionarySectionHandler" /> </sectionGroup> </configSections>

www.siteduzero.com

Partie 4 : C# avanc
<Utilisateur> <ParametreConnexion Login="Nico" MotDePasse="12345" Mode="Authentification Locale"/> <InfoPersos> <add key="prenom" value="Nicolas" /> <add key="age" value="30" /> </InfoPersos> </Utilisateur> </configuration>

345/381

Nous voyons ici que jai dfini un groupe qui sappelle Utilisateur, en utilisant la balise sectionGroup, contenant deux sections de configuration. Remarquons plus bas le contenu des sections et nous remarquons que la balise <Utilisateur> contient nos sections de configuration comme prcdemment. Pour obtenir nos valeurs de configuration, la seule chose qui change est la faon de charger la section. Ici, nous mettons le nom de la section prcde du nom du groupe. Ce qui donne : Code : C# Hashtable section1 = (Hashtable)ConfigurationManager.GetSection("Utilisateur/ParametreConnexion"); Hashtable section2 = (Hashtable)ConfigurationManager.GetSection("Utilisateur/InfoPersos");

Aprs, la faon de rcuprer les valeurs de configuration de chaque section reste la mme. Avouez que cest quand mme plus clair non ?

Crer une section de configuration personnalise


Nous allons tudier rapidement comment crer des sections de configuration personnalises. Pour cela, il faut crer une section en drivant de la classe ConfigurationSection. La classe ConfigurationSection permet de reprsenter une section dun fichier de configuration. Donc, en toute logique, nous pouvons enrichir cette classe avec nos proprits. Il suffit pour cela de dcorer nos propres proprits avec lattribut ConfigurationProperty. Ce qui donne : Code : C# public class PersonneSection : ConfigurationSection { [ConfigurationProperty("age", IsRequired = true)] public int Age { get { return (int)this["age"]; } set { this["age"] = value; } } [ConfigurationProperty("prenom", IsRequired = true)] public string Prenom { get { return (string)this["prenom"]; } set { this["prenom"] = value; } } }

Le grand intrt ici est de pouvoir typer les proprits. Ainsi, nous pouvons avoir une section de configuration qui travaille avec un entier par exemple. Tout est fait par la classe mre ici et il suffit dutiliser ses proprits indexes en y accdant par son nom. Pour que notre section personnalise soit reconnue, il faut la dclarer avec notre nouveau type : Code : XML

www.siteduzero.com

Partie 4 : C# avanc
<configSections> <section name="PersonneSection" type="MaPremiereApplication.PersonneSection, MaPremiereApplication" /> </configSections>

346/381

Le nom du type est constitu du nom complet du type (espace de nom + nom de la classe) suivi dune virgule et du nom de lassembly. Ici, lespace de nom est le mme que lassembly car jai cr mes classes la racine du projet. Si vous avez un doute, vous devez vrifier lespace de nom dans lequel est dclare la classe. Ensuite, nous pourrons dfinir notre section, ce qui donne au final : Code : XML <configuration> <configSections> <section name="PersonneSection" type=" MaPremiereApplication.PersonneSection, MaPremiereApplication " /> </configSections> <PersonneSection prenom="nico" age="30"/> </configuration>

Pour accder aux informations contenues dans la section, il faudra charger la section comme dhabitude : Code : C# PersonneSection section = (PersonneSection)ConfigurationManager.GetSection("PersonneSection"); Console.WriteLine(section.Prenom + " a " + section.Age + " ans");

Ce qui est intressant de remarquer ici, cest quon accde directement nos proprits via notre section personnalise. Ce qui est une grande force et permet de travailler avec un entier et une chaine de caractres ici. Il faudra faire attention deux choses ici. La premire est la casse. Comme on la vu dans le code, le nom est crit en minuscule. Il faudra tre cohrent entre le nom indiqu dans lattribut ConfigurationProperty, celui indiqu en paramtre de loprateur dindexation et celui crit dans le fichier de configuration. Tout doit tre orthographi de la mme faon, sinon nous aurons une exception du genre :

www.siteduzero.com

Partie 4 : C# avanc

347/381

De mme, si nous ne saisissons pas une valeur entire dans lattribut age, il va y avoir un problme de conversion :

Crer une section personnalise avec une collection


Dans le paragraphe du dessus, on constate quon ne peut dfinir quun lment dans notre section. Il pourrait tre intressant dans certains cas d'avoir une section personnalise qui puisse contenir plusieurs lments, par exemple pour avoir une liste de personnes. Pour ce faire, on utilisera la classe ConfigurationPropertyCollection. La premire chose est de crer un lment en drivant de la classe ConfigurationElement. Cet lment va ressembler beaucoup ce quon a fait pour crer une section personnalise : Code : C# public class ClientElement : ConfigurationElement { private static readonly ConfigurationPropertyCollection _proprietes;

www.siteduzero.com

Partie 4 : C# avanc
private static readonly ConfigurationProperty age; private static readonly ConfigurationProperty prenom; static ClientElement() { prenom = new ConfigurationProperty("prenom", typeof(string), null, ConfigurationPropertyOptions.IsKey); age = new ConfigurationProperty("age", typeof(int), null, ConfigurationPropertyOptions.IsRequired); _proprietes = new ConfigurationPropertyCollection { prenom, age }; } public string Prenom { get { return (string)this["prenom"]; } set { this["prenom"] = value; } } public int Age { get { return (int)this["age"]; } set { this["age"] = value; } } protected override ConfigurationPropertyCollection Properties { get { return _proprietes; } }

348/381

Ici, je dfinis deux proprits, Prenom et Age, qui me permettent bien sr dy stocker un prnom et un ge qui sont respectivement une chaine de caractres et un entier. noter que nous avons besoin de dcrire ces proprits dans le constructeur statique de la classe. Pour cela, il faut lui indiquer son nom, cest--dire la chaine qui sera utilise comme attribut dans llment de la section de configuration. Puis nous lui indiquons son type, pour cela on utilise le mot-cl typeof qui permet justement de renvoyer le type (dans le sens objet Type) dun type. Enfin nous lui indiquons une option, par exemple le prnom sera la cl de mon lment (qui est une valeur unique et obligatoire saisir) et lge, qui sera un lment obligatoire saisir galement. Ensuite, nous avons besoin dutiliser cette classe travers une collection dlments. Pour ce faire, il faut crer une classe qui drive de ConfigurationElementCollection : Code : C# public class ClientElementCollection : ConfigurationElementCollection { public override ConfigurationElementCollectionType CollectionType { get { return ConfigurationElementCollectionType.BasicMap; } } protected override string ElementName { get { return "Client"; } } protected override ConfigurationPropertyCollection Properties { get { return new ConfigurationPropertyCollection(); } } public ClientElement this[int index] { get { return (ClientElement)BaseGet(index); } set {

www.siteduzero.com

Partie 4 : C# avanc
if (BaseGet(index) != null) { BaseRemoveAt(index); } BaseAdd(index, value);

349/381

public new ClientElement this[string nom] { get { return (ClientElement)BaseGet(nom); } } public void Add(ClientElement item) { BaseAdd(item); } public void Remove(ClientElement item) { BaseRemove(item); } public void RemoveAt(int index) { BaseRemoveAt(index); } public void Clear() { BaseClear(); } protected override ConfigurationElement CreateNewElement() { return new ClientElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((ClientElement)element).Prenom; } }

Ces classes ont toujours la mme structure. Ce qui est important de voir est quon utilise lintrieur la classe ClientElement pour indiquer le type de la collection. Nous indiquons galement le nom de la balise qui sera utilise dans le fichier de configuration, cest la chaine Client que renvoie la proprit ElementName. Enfin, jai la possibilit de dfinir ma cl en substituant la mthode GetElementKey. Le reste des mthodes appellent les mthodes de la classe mre. Enfin, il faut crer notre section personnalise, qui drive comme dhabitude de ConfigurationSection : Code : C# public class ListeClientSection : ConfigurationSection { private static readonly ConfigurationPropertyCollection proprietes; private static readonly ConfigurationProperty liste; static ListeClientSection() { liste = new ConfigurationProperty(string.Empty, typeof(ClientElementCollection), null, ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsDefaultCollection);

www.siteduzero.com

Partie 4 : C# avanc
} proprietes = new ConfigurationPropertyCollection { liste };

350/381

public ClientElementCollection Listes { get { return (ClientElementCollection)base[liste]; } } public new ClientElement this[string nom] { get { return Listes[nom]; } } protected override ConfigurationPropertyCollection Properties { get { return proprietes; } }

Notons dans cette classe comment nous utilisons loprateur dindexation pour renvoyer un lment partir de sa cl et renvoyer la liste des lments. Maintenant, nous pouvons crire notre configuration : Code : XML <configuration> <configSections> <section name="ListeClientSection" type="MaPremiereApplication.ListeClientSection, MaPremiereApplication" /> </configSections> <ListeClientSection> <Client prenom="Nicolas" age="30"/> <Client prenom="Jrmie" age="20"/> </ListeClientSection> </configuration>

Nous avons besoin nouveau de dfinir la section en indiquant son type. Puis nous pouvons crer notre section et positionner notre liste de clients. Pour accder cette section, nous pouvons charger notre section comme avant avec la mthode GetSection : Code : C# ListeClientSection section = (ListeClientSection)ConfigurationManager.GetSection("ListeClientSection");

Puis nous pouvons soit itrer sur les lments de notre section : Code : C# foreach (ClientElement clientElement in section.Listes) { Console.WriteLine(clientElement.Prenom + " a " + clientElement.Age + " ans"); }

www.siteduzero.com

Partie 4 : C# avanc
Soit accder un lment partir de sa cl : Code : C# ClientElement elementNicolas = section["Nicolas"]; Console.WriteLine(elementNicolas.Prenom + " a " + elementNicolas.Age + " ans"); ClientElement elementJeremie = section["Jrmie"]; Console.WriteLine(elementJeremie.Prenom + " a " + elementJeremie.Age + " ans");

351/381

Ce qui donnera : Code : Console Nicolas a 30 ans Jrmie a 20 ans

V pour ce petit tour sur la configuration dune application. Nous y avons dcouvert plusieurs faons dy stocker des oil paramtres utilisables par notre application. Il faut savoir que beaucoup de composants du framework .NET sont intimement lis ce fichier de configuration, comme une application web cre avec ASP.NET ou lorsquon utilise des services web. Il est important de remarquer que ce fichier est un fichier de configuration dapplication. Il y a dautres endroits du mme genre pour stocker de la configuration pour les applications .NET, comme le machine.config qui est un fichier de configuration partag par toutes les applications de la machine. Il y a un hritage entre les diffrents fichiers de configuration. Si lon dfinit une configuration au niveau machine (dans le machine.config), il est possible de la redfinir pour notre application (app.config). En gnral, le fichier machine.config se trouve dans le rpertoire dinstallation du framework .NET, c'est- -dire dans un sous rpertoire du systme dexploitation, dpendant de la version du framework .NET installe. Chez moi par exemple, il se trouve dans le rpertoire : C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config. Enfin, remarquons quil est possible de faire des modifications du fichier de configuration directement depuis le code de notre application. Cest un point qui est rarement utilis et que jai choisi de ne pas prsenter pour que le chapitre ne soit pas trop long.

En rsum
Les fichiers de configuration sont des fichiers XML qui possdent les paramtres de configuration de notre application. Pour les applications console, ils s'appellent app.config. On peut dfinir toutes sortes de valeurs de configuration grce aux sections prdfinies ou en ajoutant son propre type de section personnalise.

www.siteduzero.com

Partie 4 : C# avanc

352/381

Introduction LINQ
LINQ signifie Language INtegrated Query. C'est un ensemble d'extensions du langage permettant de faire des requtes sur des donnes en faisant abstraction de leur type. Il permet d'utiliser facilement un jeu d'instructions supplmentaires afin de filtrer des donnes, faire des slections, etc. Il existe plusieurs domaines d'applications pour LINQ : Linq To Entities ou Linq To SQL qui utilisent ces extensions de langage sur les bases de donnes. Linq To XML qui utilise ces extensions de langage pour travailler avec les fichiers XML. Linq To Object qui permet de travailler avec des collections d'objets en mmoire.

L'tude de LINQ ncessiterait un livre en entier, aussi nous allons nous concentrer sur la partie qui va le plus nous servir en tant que dbutant et qui va nous permettre de commencer travailler simplement avec cette nouvelle syntaxe, savoir Linq To Object. Il s'agit d'extensions permettant de faire des requtes sur les objets en mmoire et notamment sur toutes les listes ou collections. En fait, sur tout ce qui implmente IEnumerable<>.

Les requtes Linq

Les requtes Linq proposent une nouvelle syntaxe permettant dcrire des requtes qui ressemblent de loin des requtes SQL. Pour ceux qui ne connaissent pas le SQL, il sagit dun langage permettant de faire des requtes sur les bases de donnes. Pour utiliser ces requtes, il faut ajouter lespace de noms adquat, savoir : Code : C# using System.Linq;

Ce using est en gnral inclus par dfaut lorsquon cre un nouveau fichier. Jusqu maintenant, si nous voulions afficher les entiers dune liste dentiers qui sont strictement suprieur 5, nous aurions fait : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; foreach (int i in liste) { if (i > 5) { Console.WriteLine(i); } }

Grce Linq To Object, nous allons pouvoir filtrer en amont la liste afin de ne parcourir que les entiers qui nous intressent, en faisant : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requeteFiltree = from i in liste where i > 5 select i; foreach (int i in requeteFiltree) { Console.WriteLine(i); }

Qui donnera :

www.siteduzero.com

Partie 4 : C# avanc
Code : Console 6 9 15 8

353/381

Nous avons ici cr une requte Linq qui contient des mots-cls, comme from, in, where et select. Ici, cette requte veut dire que nous partons (from) de la liste liste en analysant chaque entier de la liste dans (in) la variable i o (where) i est suprieur 5. Dans ce cas, il est slectionn comme faisant partie du rsultat de la requte grce au mot-cl select, qui fait un peu office de return. Cette requte renvoie un IEnumerable<int>. Le type gnrique est ici le type int car cest le type de la variable i qui est retourne par le select. Le fait de renvoyer un IEnumerable<> va permettre potentiellement de rutiliser le rsultat de cette requte pour un filtre successif ou une expression diffrente. En effet, Linq travaille sur des IEnumerable<> Nous pourrions par exemple ordonner cette liste par ordre croissant grce au mot-cl orderby. Cela donnerait : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requeteFiltree = from i in liste where i > 5 select i; IEnumerable<int> requeteOrdonnee = from i in requeteFiltree orderby i select i; foreach (int i in requeteOrdonnee) { Console.WriteLine(i); }

qui pourrait galement scrire en une seule fois avec : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requete = from i in liste where i > 5 orderby i select i; foreach (int i in requete) { Console.WriteLine(i); }

Et nous aurons : Code : Console 6 8 9 15

Lintrt est que grce ces syntaxes, nous pouvons combiner facilement plusieurs filtres et construire des requtes plus ou

www.siteduzero.com

Partie 4 : C# avanc
moins complexes. Par exemple, imaginons des clients : Code : C# public class Client { public int Identifiant { get; set; } public string Nom { get; set; } public int Age { get; set; } }

354/381

que lon souhaiterait savoir majeurs, puis tris par Age puis par Nom, nous pourrions faire : Code : C# List<Client> listeClients = new List<Client> { new Client { Identifiant = 1, Nom = "Nicolas", Age = 30}, new Client { Identifiant = 2, Nom = "Jrmie", Age = 20}, new Client { Identifiant = 3, Nom = "Delphine", Age = 30}, new Client { Identifiant = 4, Nom = "Bob", Age = 10} }; IEnumerable<string> requete = from client in listeClients where client.Age > 18 orderby client.Age, client.Nom select client.Nom; foreach (string prenom in requete) { Console.WriteLine(prenom); }

Ce qui donnera : Code : Console Jrmie Delphine Nicolas

Notez ici que mon select renvoie le nom du client, qui est un string. Il est donc normal que ma requte renvoie un IEnumerable<string> car jai choisi quelle ne slectionne que les noms, qui sont de type string. Il est assez frquent de construire des objets anonymes lintrieur dune requte. Par exemple, plutt que de renvoyer uniquement le nom du client, je pourrais galement renvoyer lAge, mais comme je nai pas besoin de lidentifiant, je peux crer un objet anonyme juste avec ces deux proprits : Code : C# List<Client> listeClients = new List<Client> { new Client { Identifiant = 1, Nom = "Nicolas", Age = 30}, new Client { Identifiant = 2, Nom = "Jrmie", Age = 20}, new Client { Identifiant = 3, Nom = "Delphine", Age = 30}, new Client { Identifiant = 4, Nom = "Bob", Age = 10}, };

www.siteduzero.com

Partie 4 : C# avanc
var requete = from client in listeClients where client.Age > 18 orderby client.Age , client.Nom select new { client.Nom, client.Age }; foreach (var obj in requete) { Console.WriteLine("{0} a {1} ans", obj.Nom, obj.Age); }

355/381

Et nous aurons : Code : Console Jrmie a 20 ans Delphine a 30 ans Nicolas a 30 ans

Mon objet anonyme contient ici juste une proprit Nom et une proprit Age. noter que je suis oblig ce moment-l dutiliser le mot-cl var pour dfinir la requte, car je nai pas de type donner cette requte. De mme, dans le foreach je dois utiliser le mot-cl var pour dfinir le type anonyme. Les requtes peuvent tre de plus en plus compliques, comme faisant des jointures. Par exemple, rajoutons une classe Commande : Code : C# public class Commande { public int Identifiant { get; set; } public int IdentifiantClient { get; set; } public decimal Prix { get; set; } }

Je peux crer des commandes pour des clients : Code : C# List<Client> listeClients = new List<Client> { new Client { Identifiant = 1, Nom = "Nicolas", Age = 30}, new Client { Identifiant = 2, Nom = "Jrmie", Age = 20}, new Client { Identifiant = 3, Nom = "Delphine", Age = 30}, new Client { Identifiant = 4, Nom = "Bob", Age = 10}, }; List<Commande> listeCommandes { new Commande{ Identifiant 150.05M}, new Commande{ Identifiant 30M}, new Commande{ Identifiant 99.99M}, new Commande{ Identifiant 100M}, new Commande{ Identifiant 80M}, new Commande{ Identifiant 10M}, = new List<Commande> = 1, IdentifiantClient = 1, Prix = = 2, IdentifiantClient = 2, Prix = = 3, IdentifiantClient = 1, Prix = = 4, IdentifiantClient = 1, Prix = = 5, IdentifiantClient = 3, Prix = = 6, IdentifiantClient = 3, Prix =

www.siteduzero.com

Partie 4 : C# avanc
};

356/381

Et grce une jointure, rcuprer avec ma requte le nom du client et le prix de sa commande : Code : C# var liste = from commande in listeCommandes join client in listeClients on commande.IdentifiantClient equals client.Identifiant select new { client.Nom, commande.Prix }; foreach (var element in liste) { Console.WriteLine("Le client {0} a pay {1}", element.Nom, element.Prix); }

Ce qui donne : Code : Console Le Le Le Le Le Le client client client client client client Nicolas a pay 150,05 Jrmie a pay 30 Nicolas a pay 99,99 Nicolas a pay 100 Delphine a pay 80 Delphine a pay 10

On utilise le mot-cl join pour faire la jointure entre les deux listes puis on utilise le mot-cl on et le mot-cl equals pour indiquer sur quoi on fait la jointure. noter que ceci peut se raliser en imbriquant galement les from et en filtrant sur lgalit des identifiants clients : Code : C# var liste = from commande in listeCommandes from client in listeClients where client.Identifiant == commande.IdentifiantClient select new { client.Nom, commande.Prix }; foreach (var element in liste) { Console.WriteLine("Le client {0} a pay {1}", element.Nom, element.Prix); }

Il est intressant de pouvoir regrouper les objets qui ont la mme valeur. Par exemple pour obtenir toutes les commandes, groupes par client, on ferra : Code : C# var liste = from commande in listeCommandes group commande by commande.IdentifiantClient; foreach (var element in liste) { Console.WriteLine("Le client : {0} a ralis {1} commande(s)",

www.siteduzero.com

Partie 4 : C# avanc
element.Key, element.Count()); foreach (Commande commande in element) { Console.WriteLine("\tPrix : {0}", commande.Prix); } }

357/381

Ici, cela donne : Code : Console Le client : 1 a ralis 3 commande(s) Prix : 150,05 Prix : 99,99 Prix : 100 Le client : 2 a ralis 1 commande(s) Prix : 30 Le client : 3 a ralis 2 commande(s) Prix : 80 Prix : 10

Il est possible de cumuler le group by avec notre jointure prcdente histoire davoir galement le nom du client : Code : C# var liste = from commande in listeCommandes join client in listeClients on commande.IdentifiantClient equals client.Identifiant group commande by new {commande.IdentifiantClient, client.Nom}; foreach (var element in liste) { Console.WriteLine("Le client {0} ({1}) a ralis {2} commande(s)", element.Key.Nom, element.Key.IdentifiantClient, element.Count()); foreach (Commande commande in element) { Console.WriteLine("\tPrix : {0}", commande.Prix); } }

Et nous obtenons : Code : Console Le client Nicolas (1) a ralis 3 commande(s) Prix : 150,05 Prix : 99,99 Prix : 100 Le client Jrmie (2) a ralis 1 commande(s) Prix : 30 Le client Delphine (3) a ralis 2 commande(s) Prix : 80 Prix : 10

noter que le group by termine la requte, un peu comme le select. Ainsi, si lon veut slectionner quelque chose aprs le

www.siteduzero.com

Partie 4 : C# avanc
group by, il faudra utiliser le mot-cl into et la syntaxe suivante : Ce qui donnera : Code : C# var liste = from commande in listeCommandes join client in listeClients on commande.IdentifiantClient equals client.Identifiant group commande by new {commande.IdentifiantClient, client.Nom} into commandesGroupees select new { commandesGroupees.Key.IdentifiantClient, commandesGroupees.Key.Nom, NombreDeCommandes = commandesGroupees.Count() }; foreach (var element in liste) { Console.WriteLine("Le client {0} ({1}) a ralis {2} commande(s)", element.Nom, element.IdentifiantClient, element.NombreDeCommandes); }

358/381

Avec pour rsultat : Code : Console Le client Nicolas (1) a ralis 3 commande(s) Le client Jrmie (2) a ralis 1 commande(s) Le client Delphine (3) a ralis 2 commande(s)

Lintrt dutiliser le mot-cl into est galement de pouvoir enchainer avec une autre jointure ou autre filtre permettant de continuer la requte. Il est galement possible dutiliser des variables lintrieur des requtes grce au mot-cl let. Cela va nous permettre de stocker des rsultats temporaires pour les rutiliser ensuite : Code : C# var liste = from commande in listeCommandes join client in listeClients on commande.IdentifiantClient equals client.Identifiant group commande by new {commande.IdentifiantClient, client.Nom} into commandesGroupees let total = commandesGroupees.Sum(c => c.Prix) where total > 50 orderby total select new { commandesGroupees.Key.IdentifiantClient, commandesGroupees.Key.Nom, NombreDeCommandes = commandesGroupees.Count(), PrixTotal = total }; foreach (var element in liste) { Console.WriteLine("Le client {0} ({1}) a ralis {2} commande(s) pour un total de {3}", element.Nom, element.IdentifiantClient, element.NombreDeCommandes, element.PrixTotal); }

www.siteduzero.com

Partie 4 : C# avanc

359/381

Par exemple, ici jutilise le mot-cl let pour stocker le total dune commande groupe dans la variable total (nous verrons la mthode Sum() un tout petit peu plus bas), ce qui me permet ensuite de filtrer avec un where pour obtenir les commandes dont le total est suprieur 50 et de les trier par ordre de prix croissant. Ce qui donne : Code : Console Le client Delphine (3) a ralis 2 commande(s) pour un total de 90 Le client Nicolas (1) a ralis 3 commande(s) pour un total de 350,04

Nous allons nous arrter l pour cet aperu des requtes LINQ. Nous avons pu voir que le C# dispose dun certain nombre de mots-cls qui permettent de manipuler nos donnes de manire trs puissante mais dune faon un peu inhabituelle. Cette faon dcrire des requtes LINQ sappelle en anglais la sugar syntax , que lon peut traduire par sucre syntaxique . Il dsigne de manire gnrale les constructions d'un langage qui facilitent la rdaction du code sans modifier l'expressivit du langage. V oyons prsent ce quil y a derrire cette jolie syntaxe.

Les mthodes dextensions Linq


En fait, toute la sugar syntax que nous avons vue prcdemment repose sur un certain nombre de mthodes dextensions qui travaillent sur les types IEnumerable<T>. Par exemple, la requte suivante : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requeteFiltree = from i in liste where i > 5 select i; foreach (int i in requeteFiltree) { Console.WriteLine(i); }

s'crit vritablement : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requeteFiltree = liste.Where(i => i > 5); foreach (int i in requeteFiltree) { Console.WriteLine(i); }

Nous utilisons la mthode dextensions Where() en lui fournissant une expression lambda servant de prdicat pour filtrer la liste. Cest de cette faon que le compilateur traduit la sugar syntax. Elle nest donc quune faon plus jolie dutiliser ces mthodes dextensions. Chaque mthode dextension renvoie un IEnumerable<T> ce qui permet denchainer facilement les filtres successifs. Par exemple, rajoutons une date et un nombre darticles notre classe Commande : Code : C# public class Commande

www.siteduzero.com

Partie 4 : C# avanc
{ public public public public public int Identifiant { get; set; } int IdentifiantClient { get; set; } decimal Prix { get; set; } DateTime Date { get; set; } int NombreArticles { get; set; }

360/381

Avec la requte suivante : Code : C# IEnumerable<Commande> commandesFiltrees = listeCommandes. Where(commande => commande.Prix > 100). Where(commande => commande.NombreArticles > 10). OrderBy(commande => commande.Prix). ThenBy(commande => commande.DateAchat);

Nous pouvons obtenir les commandes dont le prix est suprieur 100, o le nombre darticles est suprieur 10, tries par prix puis par date dachat. De plus, ces mthodes dextensions font beaucoup plus de choses que ce que lon peut faire avec la sugar syntax. Il existe pas mal de mthodes intressantes, que nous ne pourrons pas toutes tudier. Regardons par exemple la mthode Sum() (qui a t utilise dans le paragraphe prcdent) qui permet de faire la somme des lments dune liste ou la mthode Average() qui permet de faire la moyenne : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; Console.WriteLine("Somme : {0}", liste.Sum()); Console.WriteLine("Moyenne : {0}", liste.Average());

Qui nous renvoie dans ce cas : Code : Console Somme : 51 Moyenne : 6,375

Tout est dj fait , pratique ! videmment, les surcharges de ces deux mthodes dextensions ne fonctionnent quavec des types int ou double ou decimal Qui envisagerait de faire une moyenne sur une chaine ? Par contre, il est possible de dfinir une expression lambda dans la mthode Sum() afin de faire la somme sur un lment dun objet, comme le prix de notre commande : Code : C# decimal prixTotal = listeCommandes.Sum(commande => commande.Prix);

www.siteduzero.com

Partie 4 : C# avanc

361/381

Dautres mthodes sont bien utiles. Par exemple la mthode dextension Take() nous permet de rcuprer les X premiers lments dune liste : Code : C# IEnumerable<Client> extrait = listeClients.OrderByDescending(client => client.Age).Take(5);

Ici, je trie dans un premier temps ma liste par ge dcroissant, et je prends les 5 premiers. Ce qui signifie que je prends les 5 plus vieux clients de ma liste. Et sil y en a que 3 ? et bien il prendra uniquement les 3 premiers. Suivant le mme principe, on peut utiliser la mthode First() pour obtenir le premier lment dune liste : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; int premier = liste.Where(i => i > 5).First();

O jobtiens le premier lment de la liste qui est strictement suprieur 5. noter que le filtre peut galement se faire dans lexpression lambda de la mthode First() : Code : C# int premier = liste.First(i => i > 5);

Ce qui revient exactement au mme. Attention, sil ny a aucun lment dans la liste, alors la mthode First() lve lexception : Code : Console

Exception non gre : System.InvalidOperationException: La squence ne contient aucun l

Il est possible dans ce cas-l dviter une exception avec la mthode FirstOrDefault() qui renvoie la valeur par dfaut du type de la liste (0 si cest un type valeur, null si cest un type rfrence) : Code : C# Client nicolas = listeClients.FirstOrDefault(client => client.Nom == "Nicolas"); if (nicolas == null) Console.WriteLine("Client non trouv");

Ici, je cherche le premier des clients dont le nom est Nicolas. Sil nest pas trouv, alors FirstOrDefault() me renvoie null, sinon, il me renvoie bien sr le bon objet Client. Dans le mme genre, nous pouvons compter grce la mthode Count() le nombre dlments dune source de donnes suivant un critre : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
int nombreClientsMajeurs = listeClients.Count(client => client.Age >= 18);

362/381

Ici, jobtiendrais le nombre de clients majeurs dans ma liste. De la mme faon quavec la sugar syntax, il est possible de faire une slection prcise des donnes que lon souhaite extraire, grce la mthode Select() : Code : C# var requete = listeClients.Where(client => client.Age >= 18).Select(client => new { client.Age, client.Nom }) ;

Cela me permettra dobtenir une requte contenant les clients majeurs. noter quil y a aura dedans des objets anonymes possdant une proprit Age et une proprit Nom. Bien sr, nous retrouverons nos jointures avec la mthode dextension Join() ou les groupes avec la mthode GroupBy(). Il existe beaucoup de mthodes dextensions et il nest pas envisageable dans ce tutoriel de toutes les dcrire. Je vais finir en vous parlant des mthodes ToList() et ToArray() qui comme leurs noms le suggrent, permettent de forcer la requte tre mise dans une liste ou dans un tableau : Code : C# List<Client> lesPlusVieuxClients = listeClients.OrderByDescending(client => client.Age).Take(5).ToList();

ou Code : C# Client[] lesPlusVieuxClients = listeClients.OrderByDescending(client => client.Age).Take(5).ToArray();

Plutt que davoir un IEnumerable<>, nous obtiendrons cette fois-ci une List<> ou un tableau. Le fait dutiliser ces mthodes dextensions a des consquences que nous allons dcrire.

Excution diffre
Alors, les mthodes dextensions LINQ ou sa syntaxe sucre cest bien joli, mais quel est lintrt de sen servir plutt que dutiliser des boucles foreach, des if ou autres choses ? Dj, parce quil y a plein de choses dj toutes faites, la somme, la moyenne, la rcupration de X lments, etc. Mais aussi pour une autre raison plus importante : lexcution diffre. Nous en avons dj parl, lexcution diffre est possible grce au mot-cl yield. Les mthodes dextensions Linq utilisent fortement ce principe. Cela veut dire que lorsque nous construisons une requte, elle nest pas excute tant quon itre pas sur le contenu de la requte. Ceci permet de stocker la requte, dempiler ventuellement des filtres ou des jointures et de ne pas calculer le rsultat tant quon nen a pas explicitement besoin. Ainsi, imaginons que nous souhaitions trier une liste dentiers, avant nous aurions fait : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; liste.Sort(); liste.Add(7);

www.siteduzero.com

Partie 4 : C# avanc
foreach (int i in liste) { Console.WriteLine(i); }

363/381

Ce qui aurait affich en toute logique la liste trie puis la fin lentier 7 rajout, c'est--dire : Code : Console 1 3 4 5 6 8 9 15 7

Avec Linq, nous allons pouvoir faire : Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; var requete = liste.OrderBy(e => e); liste.Add(7); foreach (int i in requete) { Console.WriteLine(i); }

Et si nous excutons ce code, nous aurons : Code : Console 1 3 4 5 6 7 8 9 15

Bien que nous ayons ajout la valeur 7 aprs avoir tri la liste avec OrderBy, on se rend compte que tous les entiers sont quand mme tris lorsque nous les affichons. En effet, la requte na t excute quau moment du foreach. Ceci implique donc que le tri va tenir compte de lajout du 7 la liste. La requte est construite en mmorisant les conditions comme notre OrderBy, mais cela fonctionne galement avec un where, et tout ceci nest excut que lorsquon le demande explicitement, c'est--dire avec un foreach dans ce cas-l. En fait, tant que le C# nest pas oblig de parcourir les lments numrables alors il ne le fait pas. Ce qui permet denchainer les ventuelles conditions et viter les parcours inutiles. Par exemple, dans le cas ci-dessous, il est inutile dexcuter le premier filtre :

www.siteduzero.com

Partie 4 : C# avanc
Code : C# List<int> liste = new List<int> { 4, 6, 1, 9, 5, 15, 8, 3 }; IEnumerable<int> requete = liste.Where(i => i > 5); // plein de choses qui n'ont rien voir avec la requete requete = requete.Where(i => i > 10);

364/381

car le deuxime filtre a tout intrt tre combin au premier afin dtre simplifi. Et encore, ici, on nutilise mme pas la requte, il y a encore moins dintrt effectuer nos filtres si nous ne nous servons pas du rsultat. Ceci peut paratre inattendu, mais cest trs important dans la faon dont Linq sen sert afin doptimiser ses requtes. Ici, le parcours en mmoire pourrait paratre peu couteux, mais dans la mesure o Linq doit fonctionner aussi bien avec des objets, quavec des bases de donnes ou du XML (ou autres), cette optimisation prend tout son sens. Le maitre mot est la performance, primordial quand on accde aux bases de donnes. Cette excution diffre est garde pour le plus tard possible. C'est--dire que le fait de parcourir notre boucle va obligatoirement entrainer lvaluation de la requte afin de pouvoir retourner les rsultats cohrents. Il en va de mme pour certaines autres oprations, comme la mthode Sum(). Comment pourrions-nous faire la somme de tous les lments si nous ne les parcourons pas ? Cest aussi le cas pour les mthodes ToList() et ToArray(). Par contre, ce nest pas le cas pour les mthodes Where, ou Take, etc Il est important de connaitre ce mcanisme. Lexcution diffre est trs puissante et connatre son fonctionnement permet de savoir exactement ce que nous faisons et pourquoi nous pourrions obtenir parfois des rsultats tranges.

Rcapitulatif des oprateurs de requtes


Pour terminer avec Linq, voici un tableau rcapitulatif des diffrents oprateurs de requte. Nous ne les avons pas tous tudis ici car cela serait bien vite lassant. Mais grce leurs noms et leurs types, il est assez facile de voir quoi ils servent afin de les utiliser dans la construction de nos requtes. Type Tri des donnes Oprations ensemblistes Filtrage des donnes Oprations de quantificateur Oprations de projection Partitionnement des donnes Oprations de jointure Regroupement de donnes Oprations de gnration Oprations d'galit Oprations d'lment Conversion de types de donnes Oprations de concatnation Oprateur de requte OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse Distinct, Except, Intersect, Union OfType, Where All, Any, Contains Select, SelectMany Skip, SkipWhile, Take, TakeWhile Join, GroupJoin GroupBy, ToLookup DefaultIfEmpty, Empty, Range, Repeat SequenceEqual ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault AsEnumerable, AsQueryable, Cast, OfType, ToArray, ToDictionary, ToList, ToLookup Concat Excution diffre Oui Oui Oui Non Oui Oui Oui Oui Oui Non Non Non Oui

www.siteduzero.com

Partie 4 : C# avanc
Oprations d'agrgation Aggregate, Average, Count, LongCount, Max, Min, Sum Non

365/381

Nhsitez pas consulter la documentation de ces mthodes dextensions ou aller voir des exemples sur internet. Il y a beaucoup de choses faire avec ces mthodes. Il est important galement de bien savoir les matriser afin dviter les problmes de performances. En effet, lvaluation systmatique des expressions peut tre coteuse, surtout quand cest imbriqu dans des boucles. utiliser judicieusement. V pour ce petit aperu de Linq ! oil Rappelez-vous bien que Linq est une abstraction qui permet de manipuler des sources de donnes diffrentes. Nous avons vu son utilisation avec les objets implmentant IEnumerable<>, avec ce quon appelle Linq To Objects. Il est possible de faire du Linq en allant manipuler des donnes en base de donnes, on utilisera pour cela Linq To SQL ou Linq To Entity. De mme, il est possible de manipuler les fichiers XML avec Linq To XML. Linq apporte des mthodes dextensions et une syntaxe complmentaire afin dtre efficace avec la manipulation de sources de donnes. Sachez enfin quil est possible de requter nimporte quelle source de donnes partir du moment o un connecteur spcifique a t dvelopp. Cela a t fait par exemple pour interroger Google ou Amazon, mais aussi pour requter sur active directory, ou JSON, etc.

En rsum
Linq consiste en un ensemble dextensions du langage permettant de faire des requtes sur des donnes en faisant abstraction de leur type. Il existe plusieurs domaines d'applications de Linq, comme Linq to Object, Linq to Sql, etc. La sugar syntax ajoute des mots-cls qui permettent de faire des requtes qui ressemblent aux requtes faites avec le langage SQL. Derrire cette syntaxe se cache un bon nombre de mthodes d'extension qui tirent parti des mcanismes d'excution diffre.

www.siteduzero.com

Partie 4 : C# avanc

366/381

Les tests unitaires


Une des grandes proccupations des crateurs de logiciels est dtre certains que leur application informatique fonctionne et surtout quelle fonctionne dans toutes les situations possibles. Nous avons tous dj vu notre systme dexploitation planter, ou bien notre logiciel de traitement de texte nous faire perdre les 50 pages de rapport que nous tions en train de taper. Ou encore, un lment inattendu dans un jeu o l'on arrive passer travers un mur alors quon ne devrait pas Bref, pour tre sr que son application fonctionne, il faut faire des tests.

Quest-ce quun test unitaire et pourquoi en faire ?


Un test constitue une faon de vrifier quun systme informatique fonctionne. Tester son application cest bien. Il faut absolument le faire. Cest en gnral une pratique plutt laisse de ct et rbarbative. Il y a plusieurs faons de faire des tests. Celle qui semble la plus naturelle est celle qui se fait manuellement. On lance son application, on clique partout, on regarde si elle fonctionne. Celle que je vais prsenter ici constitue une pratique automatise visant sassurer que des bouts de code fonctionnent comme il faut et que tous les scnarios dun dveloppement sont couverts par un test. Lorsque les tests couvrent tous les scnarios dun code, nous pouvons assurer que notre code fonctionne. De plus, cela permet de faire des oprations de maintenance sur le code tout en tant certain que ce code naura pas subi de rgressions. De la mme faon, les tests sont un filet de scurit lorsquon souhaite refactoriser son code ou loptimiser. Cela permet dans certains cas davoir un guide pendant le dveloppement, notamment lorsquon pratique le TDD. Le Test Driven Development (TDD) (ou en Franais dveloppement pilot par les tests) est une mthode de dveloppement de logiciel qui prconise d'crire les tests unitaires avant d'crire le code source d'un logiciel. Nous y reviendrons ultrieurement. Un test est donc un bout de code qui permet de tester un autre code.

En gnral, un test se dcompose en trois partie, suivant le schma AAA , qui correspond aux mots anglais Arrange, Act, Assert , que lon peut traduire en franais par Arranger, Agir, Auditer. Arranger : Il sagit dans un premier temps de dfinir les objets, les variables ncessaires au bon fonctionnement de son test (initialiser les variables, initialiser les objets passer en paramtres de la mthode tester, etc.). Agir : Ensuite, il sagit dexcuter laction que lon souhaite tester (en gnral, excuter la mthode que lon veut tester, etc.) Auditer : Et enfin de vrifier que le rsultat obtenu est conforme nos attentes.

Notre premier test


Imaginons que nous voulions tester une mthode toute simple qui fait laddition entre deux nombres, par exemple la mthode suivante : Code : C# public static int Addition(int a, int b) { return a + b; }

Faire un test consiste crire des bouts de code permettant de sassurer que le code fonctionne. Cela peut-tre par exemple : Code : C# static void Main(string[] args) { // arranger int a = 1; int b = 2; // agir int resultat = Addition(a, b); // auditer if (resultat != 3)

www.siteduzero.com

Partie 4 : C# avanc
} Console.WriteLine("Le test a rat");

367/381

Ici, le test passe bien, ouf ! Pour tre complet, le test doit couvrir un maximum de situations, il faut donc tester notre code avec dautres valeurs, et ne pas oublier les valeurs limites : Code : C# static void Main(string[] args) { int a = 1; int b = 2; int resultat = Addition(a, b); if (resultat != 3) Console.WriteLine("Le test a rat"); a = 0; b = 0; resultat = Addition(a, b); if (resultat != 0) Console.WriteLine("Le test a rat"); a = -5; b = 5; resultat = Addition(a, b); if (resultat != 0) Console.WriteLine("Le test a rat"); }

V pour le principe. Ici, nous considrons avoir crit suffisamment de tests pour nous assurer que cette mthode est bien oil fonctionnelle. Bien sr, cette mthode tait par dfinition fonctionnelle, mais il est important de prendre le rflexe de tester des fonctionnalits qui sont dterminantes pour notre application. V oyons maintenant comment nous pourrions tester une mthode avec lapproche TDD. Pour rappel, lors dune approche TDD, le but est de pouvoir faire un dveloppement partir des cas de tests pralablement tablis par la personne qui exprime le besoin ou suivant les spcifications fonctionnelles. Imaginons que nous voulions tester une mthode qui calcule la factorielle dun nombre. Nous savons que la factorielle de 0 vaut 1, la factorielle de 1 vaut 1. Commenons par crire les tests : Code : C# static void Main(string[] args) { int valeur = 0; int resultat = Factorielle(valeur); if (resultat != 1) Console.WriteLine("Le test a rat"); valeur = 1; resultat = Factorielle(valeur); if (resultat != 1) Console.WriteLine("Le test a rat");

Le code ne compile pas ! Forcment, nous navons pas encore cr la mthode Factorielle. Cest la premire tape. La suite de la mthode est de faire en sorte que le test compile, mais il chouera puisque la mthode nest pas encore implmente : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
public static int Factorielle(int a) { throw new NotImplementedException(); }

368/381

Il faudra ensuite crire le code minimal qui servira faire passer nos deux tests. Cela peut-tre : Code : C# public static int Factorielle(int a) { return 1; }

Si nous excutons nos tests, nous voyons que cette mthode est fonctionnelle car ils passent tous. La suite de la mthode consiste refactoriser le code, loptimiser. Ici, il ny a rien faire tellement cest simple. On se rend compte par contre qu'on n'a pas couvert normment de cas de tests, juste des tests avec 0 et 1 c'est un peu lger... Nous savons que la factorielle de 2 vaut 2, la factorielle de 3 vaut 6, la factorielle de 4 vaut 24, ... Continuons crire des tests. (Il faut bien sr garder les anciens tests afin dtre sr quon couvre un maximum de cas) : Code : C# static void Main(string[] args) { int valeur = 0; int resultat = Factorielle(valeur); if (resultat != 1) Console.WriteLine("Le test a rat"); valeur = 1; resultat = Factorielle(valeur); if (resultat != 1) Console.WriteLine("Le test a rat"); valeur = 2; resultat = Factorielle(valeur); if (resultat != 2) Console.WriteLine("Le test a rat"); valeur = 3; resultat = Factorielle(valeur); if (resultat != 6) Console.WriteLine("Le test a rat"); valeur = 4; resultat = Factorielle(valeur); if (resultat != 24) Console.WriteLine("Le test a rat");

Et nous pouvons crire une mthode Factorielle qui fait passer ces tests : Code : C# public static int Factorielle(int a) { if (a == 2) return 2;

www.siteduzero.com

Partie 4 : C# avanc
if (a == 3) return 6; if (a == 4) return 24; return 1;

369/381

Lanons les tests, nous voyons que tout est OK. Cependant, nous nallons pas faire des if en dclinant tous les cas possible, il faut donc repasser par ltape damlioration et de refactorisation du code, afin dviter les redondances de code, damliorer les algorithmes, etc. Cette opration devient sans risque puisque le test est l pour nous assurer que la modification que lon vient de faire est sans rgression, si le test passe toujours bien sr Nous voyons que nous pouvons amliorer le code en utilisant la vraie formule de la factorielle : Code : C# public static int Factorielle(int a) { int total = 1; for (int i = 1 ; i <= a ; i ++) { total *= i; } return total; }

Ce qui permet dillustrer que par exemple la factorielle de 5 est gale 1*2*3*4*5. Relanons nos tests, ils passent tous. Parfait. Nous sommes donc certains que notre changement de code na pas altr la fonctionnalit car les tests continuent de passer. On peut mme rajouter des tests pour le plaisir, comme la factorielle de 10, histoire davoir quelque chose dun peu plus grand : Code : C# valeur = 10; resultat = Factorielle(valeur); if (resultat != 3628800) Console.WriteLine("Le test a rat");

Est-ce que cette mthode est optimisable ? Srement. Est-ce quil y a un risque optimiser cette mthode ? Aucun ! En effet, nos tests nous garantissent que sils continuent passer, alors une optimisation nentraine pas de rgression dans la fonctionnalit. On sait par exemple qu'il y a un autre moyen pour calculer une factorielle. Par exemple, pour calculer la factorielle de 5, il suffit de multiplier 5 par la factorielle de 4. Pour calculer la factorielle de 4, il faut multiplier 4 par la factorielle de 3, et ainsi de suite jusqu' arriver 1... Bref, pour obtenir une factorielle on peut se servir du rsultat de la factorielle du nombre prcdent. Ce qui peut scrire : Code : C# public static int Factorielle(int a) { if (a <= 1) return 1; return a * Factorielle(a - 1); }

Ici la mthode Factorielle est une mthode rcursive, cest--dire quelle sappelle elle-mme. Cela nous permet de

www.siteduzero.com

Partie 4 : C# avanc

370/381

dindiquer que la factorielle dun nombre correspond ce nombre multipli par la factorielle du nombre prcdent. Bien sr, il faut sarrter un moment dans la rcursion. On sarrte ici quand on atteint le chiffre 1. Pour sassurer que cette factorielle fonctionne bien, il suffit de relancer les tests. Tout est OK, cest parfait ! V donc un exemple de TDD. Bien sr, la mthode est ici pousse au maximum pour que vous compreniez lintrt de cette oil pratique. On peut gagner du temps en partant directement sur la bonne implmentation. Mais vous verrez quil y a toujours des premiers essais qui satisfont les tests mais quil sera possible damliorer rgulirement notre code. Ceci devient possible grce aux tests qui nous assurent que tout continue bien fonctionner. La pratique du TDD dpend de la faon dont le dveloppeur apprhende sa philosophie de dveloppement. Elle est prsente ici pour sensibiliser ce dernier cette pratique mais son utilisation nest pas du tout obligatoire. V pour les tests basiques. Cependant, utiliser une application console pour faire ses tests, ce nest pas trs pratique, vous en oil conviendrez. Nous avons besoin doutils !

Le framework de test
Un framework de test est aux tests ce que lIDE est au dveloppement. Il fournit un environnement structur permettant lexcution de test et des mthodes pour aider au dveloppement de ceux-ci. Il existe plusieurs frameworks de test. Microsoft dispose de son framework, mstest, qui est disponible dans les versions payantes de Visual Studio. Son intrt est quil est fortement intgr lIDE. Son dfaut est quil ne fonctionne pas avec les versions gratuites de lenvironnement de dveloppement. Comme nous sommes partis dans ce tutoriel avec la version gratuite, Visual C# Express, nous nallons pas pouvoir utiliser mstest. Par contre, il existe dautres framework de test, gratuits, comme le trs connu NUnit. NUnit est la version .NET du framework XUnit, qui se dcline pour plusieurs environnements, avec par exemple PHPUnit pour le langage PHP, JUnit, pour java, etc. Premire chose faire, installer NUnit, pour cela, rendez-vous cet emplacement pour le tlcharger : http://www.NUnit.org/? p=download. La version que jutilise dans ce tutoriel est la version 2.5.10. Dmarrez linstallation :

Linstallation est en anglais, mais assez facile suivre. Cliquez sur Next pour aller lcran suivant. Aprs avoir accept la licence, vous pouvez choisir linstallation classique :

www.siteduzero.com

Partie 4 : C# avanc

371/381

la fin de linstallation, nous pouvons voir que tout sest bien pass :

Une fois le framework de test install, nous pouvons crer un nouveau projet qui contiendra une fonctionnalit tester. Je lappelle MaBibliothequeATester. Dune manire gnrale, nous allons surtout tester des assemblys avec NUnit. Ici, je cre donc un projet de type bibliothque de classes. Ce projet ne sera donc pas excutable, car il ne sagit pas dune application console. Et dedans, je vais pouvoir crer une classe utilitaire, disons Math, qui contiendra notre fameuse mthode de calcul de factoriel : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
public static class Math { public static int Factorielle(int a) { if (a <= 1) return 1; return a * Factorielle(a - 1); } }

372/381

Puis ajoutons un nouveau projet de type bibliothque de classes o nous allons mettre nos tests unitaires, appelons le MathTests.Unit. Ce nest pas une norme absolue, mais je vous conseille de suffixer vos projets de test avec .Unit, ce qui permet de les identifier facilement. Les tests doivent se mettre dans une classe spciale. Ici aussi, pas de rgle de nommage obligatoire, mais il est intressant davoir une norme pour facilement sy retrouver. Je vous propose de nommer les classes de tests en commenant par le nom de la classe que lon doit tester, suivie du mot Tests. Ce qui donne : MathTests. Pour tre reconnue par le framework de test, la classe doit respecter un certain nombre de contrainte. Elle doit dans un premier temps tre dcore de lattribut [TestFixture]. Il sagit dun attribut qui permet NUnit de reconnaitre les classes qui contiennent des tests. Cet attribut tant dans une assembly de NUnit, vous devez rajouter une rfrence lassembly NUnit.framework :

et inclure lespace de nom adquat : Code : C# using NUnit.Framework;

Nous allons pouvoir crer des mthodes lintrieur de cette classe. De la mme faon, une mthode pourra tre reconnue comme une mthode de test si elle est dcore de lattribut [Test].

www.siteduzero.com

Partie 4 : C# avanc

373/381

Ici aussi, il est intressant de suivre une rgle de nommage afin de pouvoir identifier rapidement lintention de la mthode de test. Je vous propose le nommage suivant : MethodeTestee_EtatInitial_EtatAttendu() Par exemple, une mthode de test permettant de tester la factorielle pourrait sappeler : Code : C# [TestFixture] public class MathTests { [Test] public void Factorielle_AvecValeur3_Retourne6() { // test faire } }

Il existe plein dautres attributs que vous dcouvrirez ultrieurement. Il est temps de passer lcriture du test et surtout la vrification du rsultat. Pour cela, on utilise des mthodes de NUnit qui nous permette de vrifier par exemple quune valeur est gale une autre attendue. Cela se fait grce la mthode Assert.AreEqual() : Code : C# [Test] public void Factorielle_AvecValeur3_Retourne6() { int valeur = 3; int resultat = MaBibliothequeATester.Math.Factorielle(valeur); Assert.AreEqual(6, resultat); }

Elle permet de vrifier que la variable valeur vaut bien 6. Rajoutons tant quon y est une mthode de test qui choue : Code : C# [Test] public void Factorielle_AvecValeur10_Retourne1() { int valeur = 10; int resultat = MaBibliothequeATester.Math.Factorielle(valeur); Assert.AreEqual(1, resultat, "La valeur doit tre gale 1"); }

Il est important qu'une mthode de test ne s'occupe de tester qu'un seul cas d'une unique fonctionnalit, comme illustr juste au dessus. La premire mthode teste la fonctionnalit Factorielle pour le cas o la valeur vaut 3 et la seconde s'occupe du cas o la valeur vaut 10. V ous pouvez rajouter autant de mthodes de tests que vous le souhaitez tant qu'elle sont dcore de l'attribut [Test].

Jen ai profit pour rajouter un message qui permettra dindiquer des informations complmentaires si le test choue. Compilons maintenant notre projet et rendez-vous dans le rpertoire dinstallation de NUnit (par dfaut : C:\Program Files\NUnit 2.5.10\bin\net-2.0) et lancez lapplication NUnit.exe :

www.siteduzero.com

Partie 4 : C# avanc

374/381

La premire chose faire est de crer un nouveau projet :

Appelez-le ProjetTest par exemple. Il faut ensuite ajouter une assembly de test, allez dans Project > Add Assembly :

www.siteduzero.com

Partie 4 : C# avanc

375/381

Et allez pointer lassembly de tests, savoir MathTests.Unit.dll. NUnit analyse lassembly et fait apparaitre la liste des tests qui composent notre assembly (en se basant sur les attributs TestFixture et Test) :

Nous pouvons prsent lancer les tests en cliquant sur Run, et nous obtenons :

www.siteduzero.com

Partie 4 : C# avanc

376/381

Ce qui nous permet de voir rapidement quil y a un test qui passe (icne verte) et un test qui choue (icne rouge). Forcment, notre test ntait pas bon, il faut le rcrire. Nous voyons galement quil nous indique que le rsultat attendu tait 1 alors que le rsultat obtenu est de 3628800. Nous pouvons galement voir le message que nous avons demand dafficher en cas derreur. Le souci avec NUnit, cest qu partir du moment o il a charg la dll pour lancer les tests, il nest plus possible de faire des modifications, car toute tentative de compilation provoquera une erreur o il sera mentionn quil ne peut pas faire de modifications car le fichier est dj utilis ailleurs. Ce qui est vrai. Ce qui va nous obliger fermer NUnit et le r-ouvrir. noter que dans les versions payantes de Visual Studio, nous avons la possibilit de configurer NUnit en tant quoutil externe, ce que nous ne pouvons pas faire avec la version gratuite. Il va falloir faire avec Tristesse de la gratuit Nous pouvons cependant un peu tricher en dfinissant un vnement de post-compilation, qui consiste lancer NUnit automatiquement. Pour cela, allez dans les proprits du projet, onglet vnement de builds et tapez la commande suivante : "C:\Program Files\NUnit 2.5.10\bin\net-2.0\NUnit.exe" $(TargetFileName)

www.siteduzero.com

Partie 4 : C# avanc

377/381

Ici, nous indiquons qu'aprs la compilation, il va lancer le programme NUnit.exe en prenant en paramtre le rsultat de la compilation, reprsent par la variable interne de Visual C# Express : $(TargetFileName). Par contre, cela veut dire que NUnit va se lancer chaque compilation, ce qui nest peut-tre pas le but recherch Il faudra galement fermer NUnit avant de pouvoir faire quoi que soit dautre. noter que maintenant que nous savons faire de lintrospection sur les mthodes et les attributs dune classe, nous devrions tre capables de crer une petite application qui excute les tests automatiquement Pour en finir avec NUnit, notons quil y a beaucoup de mthodes permettant de vrifier si un rsultat est correct. Regardons les assertions suivantes : Code : C# bool b = true; Assert.IsTrue(b); string s = null; Assert.IsNull(s); int i = 10; Assert.Greater(i, 6);

Elles parlent delles-mmes. La premire permet de vrifier quune condition est vraie. La deuxime permet de vrifier la nullit dune variable. La dernire permet de vrifier que la variable est bien suprieure une autre. noter quelles ont chacune leur pendant (IsFalse, IsNotNull, Less). En regardant la compltion automatique, vous dcouvrirez dautres mthodes de vrification, mais celles-ci sont globalement suffisantes. Nous pouvons galement utiliser une syntaxe un peu plus parlante comme : Code : C# Assert.That(i, Is.EqualTo(10));

Mais cette syntaxe est peut-tre un peu plus parlante aux anglophones

www.siteduzero.com

Partie 4 : C# avanc
Il est galement possible dutiliser un attribut pour vrifier quune mthode lve bien une exception, par exemple : Code : C# [Test] [ExpectedException(typeof(FormatException))] public void ToInt32_AvecChaineNonNumerique_LeveUneException() { Convert.ToInt32("abc"); }

378/381

Dans ce cas, le test passe si la mthode lve bien une FormatException. Avant de terminer, prsentons deux attributs supplmentaires : les attributs SetUp et TearDown. Ils permettent de dcorer des mthodes qui seront appeles respectivement avant chaque test et aprs chaque test. C'est l'endroit idal pour factoriser des initialisations ou des nettoyages dont dpendent tous les tests. Code : C# [TestFixture] public class MathTests { [SetUp] public void InitialisationDesTests() { // rajouter les initialisations } [Test] public void Factorielle_AvecValeur3_Retourne6() { // test faire } [TearDown] public void NettoyageDesTests() { // nettoyer les variables, ... } }

Il existe plein dautres choses utiles dire sur NUnit, comme la description des autres attributs, ce que je ne vais pas faire ici. Nhsitez pas aller voir sur internet des informations plus pousses pour approfondir votre maitrise des tests.

Le framework de simulacre
Un framework de simulacre fournit un moyen de tester une mthode en lisolant du reste du systme. Imaginons par exemple une mthode qui permet de rcuprer la mto du jour, en allant la lire dans une base de donnes. Nous avons ici un problme car lorsque nous excutons le test le lundi, il pleut. Quand nous excutons le test le mardi, il fait beau, etc. Nous avons une information qui varie au cours du temps. Il est donc difficile de tester automatiquement que la mthode arrive bien construire la mto du jour partir de ces informations, vu quelles varient. Le but de ces frameworks est de pouvoir bouchonner le code dont notre dveloppement dpend afin de pouvoir le tester unitairement, sans dpendance et isol du reste du systme. Cela veut dire que dans notre test, nous allons remplacer la lecture en base de donnes par une fausse mthode qui renvoie toujours quil fait beau. Cependant, ceci doit se faire sans modifier notre application, sinon cela na pas dintrt. V quoi oil servent ces framework de simulacres. Il en existe plusieurs, plus ou moins complexe. Citons par exemple Moq (prononcez moque-you ) ou encore Moles (il y en a plein dautres). Lintrt de Moq est quil est simple daccs, nous allons le prsenter rapidement. Il permet de faire des choses simples et facilement. Tandis que Moles est un peu plus volu mais plus complexe prendre en main. V ous y reviendrez sans doute ultrieurement.

www.siteduzero.com

Partie 4 : C# avanc

379/381

Pour le tlcharger, rendez-vous sur : http://code.google.com/p/moq/downloads/list Pas de systme dinstallation volu, il y aura juste une dll rfrencer. Ajoutez donc la rfrence la dll moq.dll qui se trouve dans le sous-rpertoire NET40. Ensuite, pour pouvoir bouchonner facilement une classe, elle doit implmenter une interface. Imaginons la classe daccs aux donnes suivante : Code : C# public class Dal : IDal { public Meteo ObtenirLaMeteoDuJour() { // ici, c'est le code pour lire en base de donnes // mais finalement, peu importe ce qu'on y met vu qu'on va bouchonner la mthode throw new NotImplementedException(); } }

Qui implmente linterface suivante : Code : C# public interface IDal { Meteo ObtenirLaMeteoDuJour(); }

Avec lobjet Meteo suivant : Code : C# public class Meteo { public double Temperature { get; set; } public Temps Temps { get; set; } }

Et lnumration Temps suivante : Code : C# public enum Temps { Soleil, Pluie }

Nous pourrons crire un test qui bouchonne lappel la mthode ObtenirLaMeteoDuJour, qui doit normalement aller lire en base de donnes, pour renvoyer un objet la place. Pour bien montrer ce fonctionnement, jai fait en sorte que la mthode lve une exception, comme a, si on passe dedans a sera tout de suite visible. La mthode de test classique devrait tre : Code : C#

www.siteduzero.com

Partie 4 : C# avanc
[Test] public void ObtenirLaMeteoDuJour_AvecUnBouchon_RetourneSoleil() { IDal dal = new Dal(); Meteo meteoDuJour = dal.ObtenirLaMeteoDuJour(); Assert.AreEqual(25, meteoDuJour.Temperature); Assert.AreEqual(Temps.Soleil, meteoDuJour.Temps); }

380/381

Si nous excutons le test, nous aurons une exception. Utilisons maintenant Moq pour bouchonner cet appel et le remplacer par ce que lon veut : Code : C# [Test] public void ObtenirLaMeteoDuJour_AvecUnBouchon_RetourneSoleil() { Meteo fausseMeteo = new Meteo { Temperature = 25, Temps = Temps.Soleil }; Mock<IDal> mock = new Mock<IDal>(); mock.Setup(dal => dal.ObtenirLaMeteoDuJour()).Returns(fausseMeteo); IDal fausseDal = mock.Object; Meteo meteoDuJour = fausseDal.ObtenirLaMeteoDuJour(); Assert.AreEqual(25, meteoDuJour.Temperature); Assert.AreEqual(Temps.Soleil, meteoDuJour.Temps);

On utilise lobjet gnrique Mock pour crer un faux objet du type de notre interface. On utilise la mthode Setup travers une expression lambda pour indiquer que la mthode ObtenirLaMeteoDuJour retournera en fait un faux objet mto. Cela se fait tout naturellement en utilisant la mthode Returns(). Lavantage de ces constructions est que la syntaxe claire parle delle-mme partir du moment o on connait les expressions lambdas. On obtient ensuite une instance de notre objet grce la proprit Object et cest ce faux objet que nous pourrons comparer nos valeurs. Bien sr, ici, ce test na pas grand intrt. Mais il faut le voir un niveau plus gnral. Imaginons que nous ayons besoin de tester la fonctionnalit qui met en forme cet objet mto rcupr de la base de donnes ou bien lalgorithme qui nous permet de faire des statistiques sur ces donnes mtos L, nous sommes srs de pouvoir nous baser sur une valeur connue de la dpendance la base de donnes. Cela permettra galement de dcliner tous les cas possibles en changeant la valeur du bouchon et de faire les tests les plus exhaustifs possibles. Nous pouvons faire la mme chose avec les proprits. Imaginons la classe suivante dont la proprit valeur retourne un nombre alatoire : Code : C# public interface IGenerateur { int Valeur { get; } } public class Generateur : IGenerateur { private Random r; public Generateur() { r = new Random(); } public int Valeur { get {

www.siteduzero.com

Partie 4 : C# avanc
} return r.Next(0, 100);

381/381

Nous pourrions avoir besoin de bouchonner cette proprit pour quelle renvoie un nombre connu lavance. Cela se fera de la mme faon : Code : C# Mock<IGenerateur> mock = new Mock<IGenerateur>(); mock.Setup(generateur => generateur.Valeur).Returns(5); Assert.AreEqual(5, mock.Object.Valeur);

Ici, la proprit Valeur renverra toujours 5 en se moquant bien du gnrateur de nombre alatoire Je marrte l pour laperu de ce framework de simulacre. Nous avons pu voir quil pouvait facilement bouchonner des dpendances nous permettant de faciliter la mise en place de nos tests unitaires. Rappelez-vous, pour quun test soit efficace, il doit pouvoir se concentrer sur un point prcis du code sans tre embt par les dpendances ventuelles qui peuvent perturber ltat du test un instant t.

En rsum
Les tests unitaires sont un moyen efficace de tester des bouts de code dans une application afin de garantir son bon fonctionnement. Ils sont un filet de scurit permettant de faire des oprations de maintenance, de refactoring ou d'optimisation sur le code. Les frameworks de tests unitaires sont en gnral accompagns d'outils permettant de superviser le bon droulement des tests et la couverture de tests. Si vous voulez dcouvrir ce que l'on peut faire avec le C#, suivez ce lien pour avoir un aperu des diffrents types d'applications que l'on peut raliser avec le C#. En un peu plus dtaill, vous pouvez galement apprendre raliser des applications pour Windows Phone avec le C#.

www.siteduzero.com