Vous êtes sur la page 1sur 40

Bases du langage C#

Prof. M. TIMMI

Page 1

Le langage C# Aperu du langage Introduction C# possde une syntaxe trs proche de Java et donc du C. Cette partie du cours prsente les principales caractristiques du langage; et ne reprsente pas une description exhaustive de C#. A ce sujet, tant donn que C# est standardis et public, on peut facilement trouver des documents bass sur la norme complte du langage C#. Nous n'allons pas abandonner le rituel consistant montrer le programme "Hello world!" en C#. Le voici: using System; class Hello { static void Main() { Console.WriteLine("Hello, world"); } } L'extension d'un programme C# est .cs (par exemple hello.cs) Le code source du programme peut tre plac dans un ou plusieurs fichiers. Pour compiler ce programme, il faut taper la commande: csc hello.cs Ce qui produit un fichier hello.exe que l'on peut invoquer de la manire habituelle en tapant son nom sur la ligne de commande. En regardant de plus prs ce programme on peut faire plusieurs constatations: La premire ligne using System indique une rfrence au namespace ou espace de nom (voir plus loin) System fourni par la librairie de classes CLI. Par exemple, ce namespace contient la classe Console appele depuis le programme L'utilisation d'un namespace permet, entre autres, d'crire Console.WriteLine au lieu de System.Console.WriteLine. La mthode Main est un membre de la classe Hello. Le spcificateur static indique qu'il s'agit d'une mthode de classe et non d'instance. Le point d'entre pour l'excution du programme est toujours la mthode statique Main.

Afin de pouvoir crire des programmes simples utilisant la console, il est important non seulement de pouvoir afficher des informations, mais galement de les saisir. Nous allons voir quelques exemples illustrant plusieurs manires d'utiliser les fonctionnalits d'entre/sortie lies la console.
Prof. M. TIMMI Page 2

On peut galement accder aux paramtres de la ligne de commande depuis un programme. C# propose ce mcanisme de manire analogue aux autres langages:

using System; class Hello { public static void Main (string[] args) { Console.WriteLine ("Hello, {0}!", args[0]); Console.WriteLine ("Bienvenu au club"); } } Ainsi, si on tape hello Sifaw le programme affiche: Hello,Sifaw! Bienvenu au club La classe Console possde une mthode ReadLine qui retourne une chane de caractres fournie par l'utilisateur: using System; class Hello { public static void Main() { Console.Write("Entrez votre nom: "); string Nom = Console.ReadLine(); Console.WriteLine("Bonjour "+ Nom); } } Voici un exemple d'excution de ce programme: Entrez votre nom: Awsim Bonjour Awsim Voici une autre variante n'utilisant pas de variable: using System; class Hello {
Prof. M. TIMMI Page 3

public static void Main() { Console.Write("Entrez votre nom: "); Console.Write("Bonjour {0}", Console.ReadLine()); } } Types C# supporte deux sortes de types: Les types valeur qui incluent les types simples (char, int..), les types enum (numrations) et les types struct (structures) Les types rfrence qui incluent les types class (classes), interface (interfaces), delegate (dlgus) et array (tableaux)

Une variable de type valeur contient directement les donnes, alors qu'une variable de type rfrence ne contient que la rfrence un objet (un peu comme le ferait un pointeur). Voici un programme montrant la diffrence entre ces deux types: using System; class Class1 { public int Valeur = 0; } class Test { static void Main() { int val1 = 0; int val2 = val1; val2 = 123; Class1 ref1 = new Class1(); Class1 ref2 = ref1; ref2.Valeur = 123; Console.WriteLine("Valeurs: {0}, {1}", val1, val2); Console.WriteLine("Rfrences: {0}, {1}", ref1.Valeur, ref2.Valeur); } } Ce programme affiche le rsultat suivant: Valeurs: 0, 123 Rfrences: 123, 123 C# est un langage fortement typ, c'est--dire que toutes les oprations sur des variables sont effectues en tenant compte de leur type, afin de maintenir l'intgrit des donnes affectes ces variables.
Prof. M. TIMMI Page 4

Types prdfinis Le types rfrence prdfinis sont les type object et string. Le type object est le type de base duquel tous les autres types hritent. Le type string permet de travailler avec des chanes de caractres (Unicode) avec la particularit, comme Java, de ne pas pouvoir modifier la chane de caractres, une fois dfinie. Les types valeur prdfinis sont: Les types entiers signs et non signs Les types rels Le type bool (boolen). Nom long: System.Boolean Le type char (caractre) Le type decimal (pour reprsenter par exemple des donnes montaires)

L'introduction des types bool et string permet de rduire les nombreuses erreurs de programmation habituelles en C et C++. Voici un exemple courant d'erreur (parfois volontaire) signale par le compilateur C#: int i = .; ; if (i = 0) // Erreur signale car doit s'crire if (i==0) ; Le tableau suivant montre les types entiers, ainsi que leur taille et leur domaine de dfinition: Type Sbyte Byte Short Ushort Int Uint Long Ulong Char Nom long System.SByte System.Byte System.Int16 System.UInt16 System.Int32 System.UInt32 System.Int64 System.UInt64 System.Char Taille (bits) 8 8 16 16 32 32 64 64 16 Domaine de dfinition -128 127 0 255 -32768 32767 0 65535 -2147483649 2147483647 0 4294967295 -9223372036854775808 9223372036854775807 0 18446744073709551615 0 65535

Remarque: la lettre 'u' devant un type signifie "non sign". Le tableau suivant montre les types rels, leur taille, leur prcision et leur domaine de dfinition:
Prof. M. TIMMI Page 5

Type Float Double Decimal

Nom long Sytem.Single Sytem.Double Sytem.Decimal

Taille (bits) 32 64 128

Prcision 7 digits 15-16 digits 28-29 dc.

Domaine de dfinition 1.5 10-45 3.4 1038 5.0 10-324 1.7 10308

places 1.0 10-28 7.9 1028

Lors de l'utilisation de constantes littrales un suffixe peut tre utilis. Voici quelques exemples montrant comment spcifier des valeurs littrales: Type object string sbyte short int Long Byte ushort Uint ulong Description Type de base pour tous les autres types Chane de caractres (Unicode) Entier sign 8-bits Entier sign 16-bits Entier sign 32-bits Entier sign 64-bits Entier non sign 8-bits Entier non sign 16-bits Entier non sign 32-bits Entier non sign 64-bits Exemple object o = null; string s = "bonjour"; sbyte val = 24; short val = 24; int val = 24; long val1 = 24; long val2 = 54L; byte val1 = 24; ushort val1 = 24; uint val1 = 24; uint val2 = 54U; ulong val1 = 24; ulong val2 = 54U; ulong val3 = 68L; ulong val4 = 86UL; float val = 1.45F; double val1 = 1.45; double val2 = 3.23D; bool val1 = true; bool val2 = false; char val = 'w';

float double bool char decimal

Rel simple precision Rel double precision Boolen Caractre (Unicode)

Precise decimal type with 28 significant decimal val = 1.26M; digits

Le schma suivant montre la classification des types en C#:


Prof. M. TIMMI Page 6

Remarques: Tous les types sont compatibles avec le type object, c'est--dire qu'ils peuvent tre assigns des variables de type object, et toutes les oprations disponibles pour le type object leur sont galement applicables Comparons maintenant les types valeur et les types rfrence:

Prof. M. TIMMI

Page 7

Conversion de types Les conversions de types sont monnaie courante en programmation. Prenons l'exemple suivant: byte val1 = 12; byte val2 = 20; byte total; total = val1 + val2; Console.WriteLine (total); Sa compilation provoque un message du genre: "Cannot implicitely convert type 'int' to 'byte'". En effet, le rsultat du calcul est un int et non un byte. Pour placer le rsultat dans une variable de type byte il faut le reconvertir en byte. Une conversion de type peut se faire explicitement ou implicitement. Conversions implicites La conversion entre deux types peut s'effectuer de manire automatique (implicite) seulement si elle n'affecte pas la valeur convertie. Reprenons l'exemple prcdent, mais avec la variable total de type long: byte val1 = 12; byte val2 = 20; long total; total = val1 + val2; Console.WriteLine (total); Cette fois le compilateur ne gnre aucun message d'erreur. Le schma suivant donne les diverses possibilits de conversions implicites prises en charge par C#:

Prof. M. TIMMI

Page 8

Conversions explicites Pour beaucoup de conversions qui ne peuvent se faire implicitement, on a la possibilit d'utiliser le transtypage, c'est--dire une conversion explicite. En voici quelques exemples: de int en short de float en int d'un type numrique en char etc

Il convient d'tre prudent avec l'utilisation du transtypage, car cette opration force le compilateur effectuer une conversion d'o un risque d'altration des donnes. Voici un exemple typique de transtypage: long tot = 20000; int k = (int)tot; La conversion de long en int n'affecte pas la valeur 20000, car elle peut tre contenue dans une variable de type int. En revanche le code qui suit est potentiellement dangereux: long tot = 3000000000; int k = (int)tot; car la variable k contient la valeur -1294967296, ce qui est manifestement faux et rsulte de la troncation de 8 bytes 4 bytes avec "mauvaise" prise en compte du bit de signe. Une conversion courante en programmation concerne les nombres et les chanes de caractres. Le fait que la classe Object implmente une mthode ToString, qui a t remplace dans tous les type .NET prdfinis, permet d'obtenir une reprsentation littrale de l'objet: int k = 12; string s = k.ToString(); Pour effectuer la transformation inverse, c'est--dire passer d'une chane de caractres un nombre il est possible d'utiliser la mthode Parse, offerte par tous les types prdfinis: string s = "120"; int k =int.Parse(s); Console.WriteLine (k); Il faut cependant remarquer que Parse() peut provoquer une erreur, et lever une exception qu'il faut traiter, si la conversion n'est pas faisable.

Prof. M. TIMMI

Page 9

Boxing (embotage) et unboxing (dsembotage) Comme nous l'avons vu, tous les types, mme les types simples prdfinis, drivent du type Object. Cela permet de travailler avec des valeurs littrales comme s'il s'agissait d'objets: string s = 12.ToString(); Le boxing peut tre vu comme un transtypage d'un type valeur un type rfrence. Le runtime cre une "bote" temporaire de type rfrence pour l'objet sur le tas (heap). Dans l'exemple prcdent le boxing est effectu de manire implicite, mais on peut galement le faire de faon explicite comme dans: int k = 30; object obj = k;

// boxing en int

Le unboxing concerne l'opration inverse dans laquelle un type rfrence est transtyp en type valeur. int k = 30; object obj = k; // boxing d'un int en objet int j = (int)obj; // unboxing pour revenir un int

Enumrations Une numration n'est rien d'autre qu'un type entier dfini par l'utilisateur. En fait, pour plus de facilit d'utilisation, on travaille avec des noms qui, de manire implicite ou explicite sont associs des valeurs numriques. Les avantages lis l'utilisation des numrations sont multiples: maintenance du code plus aise avec la scurit d'affecter une variable uniquement des valeurs lgitimes code plus clair par l'utilisation de noms descriptifs

Voici comment dclarer une numration: enum Couleur { // valeurs: 0,1,2 rouge, bleu, vert } enum Acces { //valeursexplicites personel = 1, groupe =2,
Prof. M. TIMMI Page 10

tous = 4 } enum Acces2 : byte {// possibilit d'associer un type personel =1, groupe = 2, tous = 4 } Et comment l'utiliser: Couleur c = Couleur.bleu; Acces a = Acces.personel | Acces.groupe; if ((Acces.personel & a) != 0) Console.WriteLine("Accs accord"); Oprations avec les numrations: Il est possible d'effectuer des oprations avec les numrations: Comparaison + ++ & | ~ -if (c == Couleur.rouge) if (c > Couleur.rouge && c <= Couleur.vert) c = c + 1; c++; if ((c & Couleur.rouge) == 0) c = c | Couleur.bleu; c = ~ Couleur.rouge;

Tableaux C# traite les tableaux de manire nouvelle. Bien que la syntaxe ressemble celle que l'on trouve dans d'autres langages, leur implmentation est bien diffrente. Lors de la dclaration d'un tableau une instance de la classe .NET System.Array est cre. Le compilateur traduit les oprations habituelles sur les tableaux en appels de mthodes de System.Array.

Voici comment dclarer un tableau d'entiers: int[] entiers;


Prof. M. TIMMI Page 11

Pour initialiser un tableau de taille dfinie on peut utiliser le mot-cl new: int[] entiers = new int[20]; En C# tous les tableaux utilisent une indexation partant de zro, et l'accs aux lments du tableau s'effectue de manire habituelle: entiers[0] = 42; Avec la dclaration prcdente, le dernier lment de notre tableau est: entiers[19] C# propose galement la possibilit d'initialiser le contenu d'un tableau l'aide d'une liste de valeurs: string[] tableau ={"premier", "deuxime", "troisime"};

Utilisation des tableaux Comme les tableaux correspondent une classe sous-jacente, ils ont leurs propres mthodes et leur utilisation est facilite. Par exemple: la proprit Length permet de connatre la taille d'un tableau: int taille = entiers.Length; la mthode Sort permet de trier les lments d'un tableau s'ils sont d'un des types prdfinis Array.Sort(tableau); il est galement possible de renverser l'ordre des lments dans un tableau: Array.Reverse(tableau); Tableaux multidimensionnels En C# on trouve deux sortes de tableaux multidimensionnels:

Prof. M. TIMMI

Page 12

Tableaux rectangulaires Dans un tableau rectangulaire, par exemple deux dimensions, toutes les lignes ont le mme nombre de colonnes. Il s'agit en fait du type de tableaux que l'on trouve dans la plupart des langages de programmation, appel aussi matrice. Voici un exemple d'un tel tableau ayant 4 lignes de 2 colonnes chacune: string[,] savants = {{"Sifaw", "Sara"}, {"Ahmed","Noumidia", {"Tim","Massin"}, {"Awsim","Younes"} };

Voici un exemple d'utilisation de boucles pour initialiser les lments d'un tableau deux dimensions: double[,] matrice = new double[10,10]; for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) matrice[i,j] = 10; } Tableaux orthogonaux Cette sorte de tableau multidimensionnel est aussi appele tableau de tableaux (jagged). Ces tableaux sont plus souples d'utilisation que les tableaux rectangulaires, mais plus difficiles instancier et initialiser: int[][] a = new int[3][]; a[0] = new int[4]; a[1] = new int[3]; a[2] = new int[1]; Les itrations sur les lments d'un tableau orthogonal demandent plus de travail que pour un tableau rectangulaire. En effet, pour chaque ligne, il faut utiliser la mthode GetLength pour savoir combien la ligne possde de colonnes sur lesquelles itrer.

Prof. M. TIMMI

Page 13

Structures A l'origine une structure est une entit qui regroupe des champs dont le type peut tre diffrent. En C#, une structure ressemble une classe, avec quelques diffrences. Dclaration de structure Voici un exemple de dclaration d'une structure (mot rserv struct): struct Point { public int x, y; // champs public Point (int x,int y){// constructeur this.x = x; this.y = y; } public void MoveTo (int a, int b) { // mthodes x = a; y = b; } } Utilisation d'une structure L'utilisation d'une structure ressemble celle d'une classe: Point p = new Point(3, 4); // le constructeur initialise l'objet sur la pile p.MoveTo(10, 20); // appel de mthode

Classes La classe est le concept de base de la programmation oriente objet. Elle est prsente ici afin de la comparer la structure. On trouvera dans la suite plus d'indications concernant les classes. Dclaration d'une classe Voici comment dclarer une classe en C#: class Rectangle { Point origine; // public int largeur, hauteur; public Rectangle() { // origine = new Point(0,0); largeur = hauteur = 0; } public Rectangle (Point p, int l, int h) //autre constructeur origine = p; largeur = l; hauteur = h; } public void MoveTo (Point p) { //
Prof. M. TIMMI

champs constructeur

mthode
Page 14

origine = p; } }

Utilisation d'une classe Un exemple d'utilisation de la classe Rectangle: Rectangle r = new Rectangle(new Point(10, 20), 5, 5); int surface = r.largeur * r.hauteur; r.MoveTo(new Point(3, 3));

Diffrences entre structures et classes Le tableau qui suit montre les principales diffrences entre les structures et les classes: Structures Type valeur (objets stocks sur la pile) Pas de support de l'hritage (mais compatible avec object) Destructeurs non autoriss Classes Type rfrence (objets stocks sur le tas) Support de l'hritage (toutes les classes drivent de object) Peuvent avoir un destructeur

Espaces de dclaration
Dans cette section nous allons voir o peuvent tre dclars les objets (au sens large) d'une application. Espace de dclaration
Namespace Class, interface, struct Enum Bloc

Entits que l'on peut y dclarer


Classes, interfaces, structures, numrations, dlgus Champs, mthodes, proprits, vnements, indexeurs... Constantes d'numration Variables locales

Domaine de dfinition Les contraintes suivantes doivent tre prises en considration: Un nom ne peut tre dclar plus d'une fois dans un domaine de dclaration.
Page 15

Prof. M. TIMMI

les dclarations peuvent intervenir dans n'importe quel ordre, sauf, bien entendu, pour les variables locales qui doivent tre dclares avant d'tre utilises

Rgles de visibilit La visibilit indique depuis quelle portion de programme un objet (au sens large) est visible et donc depuis o il peut tre rfrenc. Un nom est visible uniquement dans son espace de dclaration. les variables locales sont visibles uniquement depuis ( partir de) leur point de dclaration, c'est--dire aprs leur point de dclaration, mais dans leur espace de dclaration la visibilit d'un nom peut tre restreinte l'aide de modificateurs (private, protected, ...)

Chanes de caractres Voici quelques exemples de dclarations et d'utilisation des chanes de caractres. string string string string Indications: Il n'y a pas de limite quant au nombre de caractres constituent une chane de caractres. le caractre @ devant une chane de caractres permet de dfinir un "verbatim string", c'est--dire une chane de caractres dont le contenu est pris tel quel par le compilateur. Ceci peut se rvler particulirement avantageux dans certains cas: string document = @"c:\mes documents\nouveau\exemple.doc"; La seule exception est le guillemet, car le compilateur doit reconnatre la fin de la chane de caractres: string s = @"""Salut"""; Constantes Les constantes doivent tre dclares l'aide du mot rserv const, suivi d'un type. Une valeur doit leur tre affecte au moment de la dclaration: const int noteMax = 6; const long vitesseLumiere = 300000;// km/s const double racineDeux = 1.414; // produit la chane "Salut" s s s s = = = = "Bonjour"; // Bonjour "\"Bonjour\""; //"Bonjour" "Bon\njour"; // saut de ligne ajout @"Bonjour\n"; // Bonjour\n

Prof. M. TIMMI

Page 16

Expressions et oprateurs
En programmation on utilise une expression dans le but d'effectuer une action et de retourner une valeur. Une expression est une squence d'oprateurs et d'oprandes. Un oprateur est un symbole indiquant l'action effectuer, alors qu'un oprande est la valeur sur laquelle l'opration est effectue. Exemples Oprateurs courants
Incrmentation/dcrmentation Arithmtiques ++ -* / % + -

Relationnels Conditionnels Affectation

<

>

<=

>=

==

!=

&& || ?: = *= /= %= += -= <<= >>= &= ^= |=

Priorit des oprateurs C# dispose quasiment des mmes oprateurs que C. Voici les priorits des diffrents oprateurs Groupe Primair e Unaire Multiplication/division Addition/soustraction Oprateurs binaries Relationnel Comparais on ET binaire XOR binaire OU binaire ET boolen OU boolen Oprateur ternaire Affectati on
Prof. M. TIMMI

Oprateurs (x) x.y f(x) a[x] x++ x new typeof sizeof checked unchecked + * + / ~ % ! ++x --x (T)x (transtypage)

de

dcalage

<< >> < > <= >= is as

== != & ^ | && || ? : = += -= >>>= *= /= %= &= |= ^= <<= >>=

Page 17

Oprateurs et chanes de caractres Il est possible d'utiliser les oprateurs == et + avec les chanes de caractres: string a = "trs"; string b = " bien"; string c = a + b; // trs bien if ("rouge" == "rouges")... Instructions conditionnelles Les instructions conditionnelles sont: l'instruction if ... else l'instruction switch

Une instruction conditionnelle permet de contrler le flux d'un programme en fonction de la valeur d'une expression boolenne. if ... else Une instruction conditionnelle de type if possde deux syntaxes selon que la partie else est spcifie ou non. De plus, conformment au thorme de structure, les instructions conditionnelles peuvent tre imbriques. En voici quelques exemples: // des taxes sont calcules uniquement si les ventes excdent 2000 if (ventes > 2000) { taxes = 0.072 * ventes; } if (ventes > 2000) { taxes = 0.072 * ventes; // excut si la condition est vraie } else { taxes = 0; // excut si la condition est fausse } if (ventes > 2000) { taxes = 0.072 * ventes; } else if (ventes > 1000) { taxes = 0.04 * ventes; } else {
Prof. M. TIMMI Page 18

taxes = 0; } } Une alternative parfois intressante, car concise, est l'oprateur ternaire ?: taxes = (ventes > 2000) ? (ventes * 0.072) : 0; switch L'instruction switch peut tre vue comme une instruction conditionnelle plusieurs embranchements, en fonction de diverses valeurs que peut prendre l'expression teste. switch (mois) { case 1 : jours = 31; break; case 2 : jours = 28; break; case 3 :jours = 31;break; case 4 : jours = 30; break; case 5 : jours = 31; break; ... etc } Dans ce cas, l'expression (mois) est value. Si cette valeur est gale une des constantes de case, l'excution du programme se poursuit avec l'instruction qui suit le case correspondant. Si la valeur ne correspond aucune des constantes proposes, l'excution du programme se poursuit aprs l'instruction switch. Il est galement possible de spcifier une clause default. Si la valeur ne correspond aucune des constantes proposes, l'excution du programme se poursuit avec l'instruction qui suit default : switch (mois) { case 1: jours = 31; break; case 2: jours = 28; break; case 3: jours = 31; break; case 4: jours = 30; break; case 5: jours = 31; break; ... etc default : // numro de mois incorrect break; } Il est obligatoire d'inclure l'instruction break la fin de chaque bloc (contrairement au C et C++) Il est toutefois possible de regrouper les traitements comme dans:

Prof. M. TIMMI

Page 19

switch (mois) { case 1: case 3: case 5: case 7: case 8: case 10: case 12 :jours = 31;break; case 2: jours = 28; break; default : jours = 30; break; } Instructions itratives (boucles) En C# il existe trois instructions permettant d'effectuer des boucles: l'instruction for l'instruction while l'instruction do

Nous faisons ici uniquement un bref rappel. La syntaxe et l'utilisation est la mme qu'en C, C++, Java. Instruction for La boucle for est d'une utilisation trs souple, contrairement l'quivalent en Pascal. Le plus souvent une boucle for est utilise dans les situations o l'on connat l'avance le nombre d'itrations effectuer. La syntaxe est la suivante: for (initialisation; condition; iteration) { instructions; } La condition est value et, tant qu'elle est vraie, le bloc d'instructions constituant le corps de la boucle est excut. La condition est value avant l'excution des instructions. Les exemples qui suivent illustre diverses utilisations d'une boucle for: for (int i = 0; i < { Console.WriteLine } for (int k = 200; k { Console.WriteLine } 10; i++) ("i = {0}", i); > 0; k -= 10) ("k = {0}", k);

Le compteur de boucle peut tre incrment ou dcrment; il n'est pas forcment de type entier. La partie initialisation et itration d'une boucle for peut contenir plus d'une dclaration de variable locale:
Prof. M. TIMMI Page 20

for (int i = 0, j = 100; i > 100; i++, j--) { Console.WriteLine ("{0}, {1}", i, j); } Les rsultats produits par l'excution de cette boucle sont: 0, 100 1, 99 2, 98 ... 99, 1 Instruction while Comme pour la boucle for, la boucle while est une boucle dans laquelle le test est effectu avant d'excuter les instructions de la boucle. La syntaxe est la suivante: while (condition) { instructions; } La boucle while est souvent utilise lorsque l'on ne connat pas l'avance le nombre d'itrations effectuer: bool continuer; ... while (continuer) { string res = LireElement(); // autres instructions continuer = res != "fin"; } Instruction do Contrairement aux instructions for et while, dans le cas de l'instruction do les instructions du corps de la boucle sont d'abord excutes, ensuite seulement la condition de continuation de la boucle est value. La syntaxe est la suivante: do { instructions; } while (condition); Le fait que le bloc d'instruction est de toute manire excut au moins une fois est important. Le programmeur doit prendre garde cette particularit; par exemple lorsque la condition est fausse ds le dpart ne doit pas poser de problme pour l'excution des instructions de la boucle. int somme = 0; int i = 0;
Prof. M. TIMMI Page 21

do { somme += i; } while (i <= 20); Console.WriteLine ("Somme des 20 premiers entiers: {0}, somme); Instruction break et continue Pour les trois types de boucles il est possible d'utiliser les instructions break et continue. Lorsque l'instruction continue est rencontre dans le corps d'une boucle, l'excution se poursuit directement la prochaine itration en ignorant compltement le reste des instructions du corps de la boucle. Lorsque l'instruction break est rencontre dans le corps de la boucle, l'excution de la boucle est termine et l'excution se poursuit avec l'instruction qui suit la boucle. Lorsque plusieurs instructions itratives sont imbriques, l'effet des ventuelles instructions break et continue concerne uniquement la boucle dans laquelle elles apparaissent.

Prof. M. TIMMI

Page 22

Les objets en C# Dans cette partie nous allons aborder les concepts gnraux de la programmation oriente objet, savoir les notions de classes, d'objets et de mthodes. Classes et objets De manire simple on peut essayer de dfinir une classe et un objet. Les deux notions sont bien entendu intimement lies. Classe C'est un modle partir duquel on peut crer des objets. Une classe dfinit les caractristiques d'un objet: les types de donnes que l'objet contient les mthodes dcrivant le comportement de l'objet

Ces caractristiques spcifient comment les autres objets peuvent accder et travailler avec les donnes de l'objet considr. Objet Un objet est une instance d'une classe. Il est cr partir du "modle" qu'est la classe. Dfinition d'une classe et cration d'un objet La dfinition d'une classe suit la syntaxe: [attributs] [modificateurs d'accs] class identificateur { corps } (nous reviendrons plus loin sur les attributs et les modificateurs d'accs) Dfinissons une nouvelle classe, Client, contenant trois informations (ou champs, ou encore membres): le nom, le revenu et le no. de client: class Client { public string nom; public decimal revenu; public uint clientNo; } Bien que la classe soit dfinie, il n'existe encore aucun objet Client. La dfinition d'une classe correspond crer un nouveau type dans une application. Afin d'utiliser la classe ainsi cre il faut instancier un objet de ce type, l'aide du motcl new. La syntaxe est: <classe> <objet> = new <classe> Par exemple: Client unClient = new Client();

Prof. M. TIMMI

Page 23

Accs aux variables (champs) d'une classe Aprs avoir instanci un objet, l'accs aux champs d'une classe est effectu en utilisant la notation pointe: unClient.nom = "Pierre Platte"; Remarques: rappelons qu'une classe est un type rfrence il est fortement conseill de suivre la casse Pascal pour les noms de classes (par exemple MaPremiereClasse). Chaque mot qui compose le nom commence par une majuscule lors de la cration d'un objet un emplacement mmoire est allou. A l'instar de Java, il n'est pas de la responsabilit du programmeur de dsallouer la mmoire utilise par un objet. Le garbage collector (ou ramasse-miettes) s'en charge automatiquement. Ds qu'un objet n'est plus utilis il libre la mmoire qu'il occupe. Le moment auquel cette libration intervient n'est pas prdictible. Il existe toutefois une possibilit de librer explicitement la mmoire, mais nous ne l'aborderons pas ici.

Namespaces (espaces de noms) Les namespaces servent organiser les classes dans une hirarchie logique, un peu la manire des packages de Java, mais de manire plus souple. Les namespaces ne sont pas seulement utiles dans une optique d'organisation interne, mais aussi dans le but d'viter des collisions de noms. Il est fortement probable que beaucoup de socits et de dveloppeurs ont dfini une classe qui s'appelle Client. L'utilisation de namespaces permet de lever l'ambigut des noms de classes. On peut donc dire qu'un namespace est un systme d'organisation permettant d'identifier des groupes de classes. Remarques: il est recommand d'utiliser la casse Pascal pour les noms de namespaces dans un environnement de dveloppement professionnel il est galement conseill de crer des namespaces double niveau. Un premier niveau indiquant le nom de la socit est suivi d'un second niveau spcifiant par exemple le nom du dpartement: namespace LesComptoirs.Ventes { public class Client(){ } } cette notation est quivalente la suivante, qui utilise un format imbriqu:
Prof. M. TIMMI Page 24

namespace LesComptoirs { namespace Ventes { public class Client(){ } } } et dans les deux cas la classe Client peut tre rfrence par: LesComptoirs.Ventes.Client() ce qui constitue le fully qualified name de la classe Client Les namespaces du framework .NET Le framework .NET est constitu d'un grand nombre de namespaces, dont le plus important est System. Ce namespace contient des classes que la plupart des applications utilisent pour interagir avec le systme d'exploitation. Par exemple, le namespace System contient la classe Console qui fourni divers mthodes, dont WriteLine. On peut ainsi crire: System.Console.WriteLine ("Bonjour"); Il n'y a pas de limite au nombre de niveaux d'un namespace. De ce fait, l'criture de programmes peut devenir fastidieuse et peu claire. C'est pour pallier cet inconvnient que la directive using a t introduite. Normalement au dbut des fichiers de programmes on trouve une liste des namespaces utiliss dans le fichier, prfixs par using. using System; using LesComptoirs.Ventes; Console.WriteLine ("Bonjour"); Client(); Accessibilit et domaine de visibilit (scope) Le concept de domaine de visibilit a pris toute son importance surtout depuis l'avnement de la programmation structure et des langages de programmation modernes. Pour des raisons de scurit, d'organisation et de maintenance il est important que les divers objets d'un programme n'aient pas tous la mme accessibilit. Certains doivent tre masqus, d'autres publics. Le domaine de visibilit d'un objet (au sens large) est la rgion du code d'une application depuis laquelle cet objet peut tre rfrenc. En C# les modificateurs d'accs sont utiliss dans le but de contrler leur domaine de visibilit. Le tableau suivant prsente les modificateurs d'accs disponibles pour les membres d'une classe ainsi que leur signification:

Client

unClient

new

Prof. M. TIMMI

Page 25

Dclaration Public Private

Dfinition Accs illimit. N'importe quelle autre classe peut accder un membre public Accs limit la classe contenante. Seule la classe contenant le membre peut accder au membre private. Accs limit cet assemblage (programme). Les classes se trouvant dans le mme assemblage peuvent accder au membre. Accs limit la classe contenante et aux classes drives de cette classe.

Internal

Protected protected internal

Accs limit la classe contenante, aux classes drives et aux classes se trouvant dans le mme assemblage. Un assemblage (assembly) est l'ensemble des fichiers constituant un programme. Rgles importantes: les namespaces sont toujours public (implicitement). les classes sont toujours public (implicitement). les membres sont private par dfaut. un seul modificateur d'accs peut tre dfini pour un membre de classe (protected internal est considr comme un unique modificateur). le domaine de visibilit d'un membre n'est jamais plus grand que celui du type qui le contient.

Remarques: public doit donc tre rserv aux entits que les utilisateurs d'une classe ont besoin de voir. en limitant le nombre d'entits public on diminue la complexit des classes du point de vue de l'utilisateur. Cela rend la maintenance plus aise.

Afin de mieux comprendre le concept d'accessibilit, considrons l'exemple suivant: using System; namespace CoursCSharp.Exemple { class ClassMain { public class Troll { public int age; private string couleur; }
Prof. M. TIMMI Page 26

static void Main (string[] args) { Troll tiTroll = new Troll(); tiTroll.age = 100; tiTroll.couleur = "rouge"; // erreur car couleur n'est pas accessible } } } Mthodes Une mthode est un membre d'une classe qui est utilis pour dfinir une action pouvant tre accomplie par cet objet ou classe. Syntaxe de dclaration d'une mthode: [attributs] [modificateurs d'accs] type-retour nom ([liste de paramtres]) { corps }

Rgles et recommandations: le type de retour d'une mthode doit toujours tre spcifi. Si une mthode ne retourne rien, ce type sera void. mme si une mthode ne comporte pas de paramtres son nom doit tre suivi de parenthses vides (). bien entendu lorsqu'une mthode est invoque, il faut respecter le type de la valeur retourne, ainsi que le nombre, l'ordre et le type des paramtres.

le nom d'une mthode devrait reprsenter une action. Par exemple: DiminuerAge, AlimenterTroll. il est conseill que les noms des mthodes suivent une casse Pascal.

Exemple: class Troll { private int poids; public bool TesterPoidsNormal () { if ((poids < 20) || (poids > 40)) { return false; } return true }
Prof. M. TIMMI Page 27

public void Manger () { } public int GetPoids () { return poids; }

Cration d'un objet Troll: Troll grosTroll = new Troll(); Test de son poids: if (grosTroll.TesterPoidsNormal () == false) { Console.WriteLine ("Le troll n'a pas un poids idal"); } La mthode Manger ne retourne aucune valeur. Elle pourrait tre utilise ainsi: grosTroll.Manger(); Le mot-cl this Le mot-cl this est utilis pour indiquer l'instance courante de l'objet. Nous aurions pu crire la mthode GetPoids de la manire suivante (quivalente la dfinition prcdente): public int GetPoids () { return this.poids;

Passage de paramtres Le passage de paramtres est le mcanisme permettant d'changer de l'information entre une mthode et la portion de programme appelante. Passage de paramtres par valeur Lorsqu'une variable de type valeur est passe une mthode, celle-ci reoit une copie de la valeur de cette variable:

class Troll { private int poids; public void SetPoids ( int nouveauPoids) { poids = nouveauPoids; } } ... ... Troll pasTroll = new Troll(); int lePoids = 45;
Prof. M. TIMMI Page 28

pasTroll.SetPoids (lePoids); // appel de la mthode Lors de l'appel la valeur de lePoids est copie dans le paramtre nouveauPoids (qui est en fait considre comme une variable locale la mthode). Voici un second exemple: class Champ { public int CalculerSurface (int largeur, int longueur) { return largeur * longueur; } } ... Champ monChamp = new Champ(); int surface = monChamp.CalculerSurface (40, 60); Passage de paramtres par rfrence Nous avons vu qu'une mthode retourne une valeur unique. Dans certaines situations on aimerait qu'une mthode retourne plusieurs valeurs. Il est alors possible de passer la mthode une rfrence la variable sur laquelle la mthode va travailler. Toute modification de l'objet pass la mthode sera rpercute sur l'objet la fin de l'excution de la mthode. Pour indiquer un passage de paramtre par rfrence, le mot-cl ref doit tre spcifi. Reprenons notre classe Client: class Client { public string nom = "Pierre"; public decimal revenu = 1000D; public uint clientNo = 22231; public void GetClient (ref string leNom, ref decimal leRevenu,ref unit leNo) { leNom = nom; leRevenu = revenu; leNo = clientNo; } } ... Client unClient = new Client(); string unNom = null; decimal unRevenu = 0D; uint unNo = 0; ... unClient.GetClient (ref unNom, ref unRevenu, ref unNo); On remarquera que le mot-cl ref doit galement tre spcifi lors de l'appel de la mthode.

Remarques: C# oblige que toutes les variables soient initialises avant d'tre passes
Page 29 Prof. M. TIMMI

comme paramtres une mthode. Mme si, comme dans notre exemple, la mthode initialise ces variables. C# dispose du mot-cl out permettant de spcifier au compilateur qu'un paramtre est initialis par une mthode. Dans ce cas il est possible de passer, par rfrence, une variable non initialise: class Client { public string nom = "Pierre"; public decimal revenu = 1000D; public uint clientNo = 22231; public void GetClient (out string leNom, out decimal leRevenu,out unit leNo) { leNom = nom; leRevenu = revenu; leNo = clientNo; } } ... Client unClient = new Client(); string unNom; decimal unRevenu; uint unNo; ... unClient.GetClient (out unNom, out unRevenu, out unNo); Passage d'un type rfrence comme paramtre Lorsqu'une variable de type rfrence (par exemple un objet) est passe comme paramtre une mthode, celle-ci peut altrer la valeur de cette variable. L'exemple suivant met en vidence cette caractristique: class MainClass { static void Main (string[] args) { Zoo monZoo = new Zoo(); Troll tiTroll = new Troll(); monZoo.AjouterTroll (tiTroll); // ici tiTroll.emplacement vaut "Cage no. 3"

class Troll { public string emplacement; } class Zoo { public void AjouterTroll (Troll nouveauTroll) { nouveauTroll.emplacement = "Cage no. 3"; } }

Prof. M. TIMMI

Page 30

Surcharge de mthode La surcharge de mthode (overload) est une particularit permettant, dans une mme classe, de dfinir plusieurs mthodes ayant le mme nom, mais une signature diffrente. Par signature on entend l'ensemble constitu par le nom de la mthode et ses paramtres. La classe Date comporte plusieurs mthodes surcharges: class Date { public void Ajouter (int jours); public void Ajouter (int jours, int mois, int annees); public void Ajouter (double temps); } L'utilisation de la surcharge de mthodes prsente plusieurs avantages: l'utilisation du mme nom (donc mme signification) pour plusieurs "variantes" d'actions facilit pour ajouter de nouvelles fonctionnalits en changeant uniquement la syntaxe d'appel d'une mthode fournir plusieurs constructeurs pour une classe donne (voir plus loin)

Constructeurs Un constructeur est une mthode particulire utilise pour initialiser un objet. Chaque classe intgre, de manire implicite ou explicite, un constructeur d'instance. Cette mthode est automatiquement appele lorsqu'une nouvelle instance de classe est cre. Un constructeur porte le mme nom que la classe pour et dans laquelle il est dfini. class Boisson { public Boisson() { Console.WriteLine ("Constructeur boisson"); } } Voici comment le constructeur est utilis: Boisson sirop = new Boisson(); Console.WriteLine ("Sirop cr"); on obtient le rsultat suivant: Constructeur boisson Sirop cr Il n'est pas obligatoire de spcifier un constructeur. Dans ce cas C# en fournit un par dfaut (sans paramtres): class Boisson {
Prof. M. TIMMI Page 31

private string marque; } est quivalent : class Boisson { private string marque; public Boisson() { } }

Un constructeur peut bien entendu avoir des paramtres. Si un tel constructeur est spcifi, alors aucun constructeur par dfaut n'est automatiquement cr. class Boisson { private string marque; public Boisson(string laMarque) { marque = laMarque; } } De cette manire l'utilisateur de la classe Boisson est oblig d'indiquer la marque de la boisson lorsqu'il cre une boisson: Boisson sirop = new Boisson("grenadine"); Remarques: on peut donc constater qu'un constructeur porte le nom de la classe et ne retourne rien, mme pas le type void Au niveau des constructeurs d'une classe, on peut donc se trouver dans une des situations suivantes: o aucun constructeur n'est spcifi. Le compilateur fournit automatiquement un constructeur par dfaut, sans paramtres

o un seul constructeur est spcifi. Dans ce cas, c'est ce constructeur qui sera appel. Le compilateur ne fournit pas de constructeur par dfaut o plusieurs constructeurs sont spcifis. Tous les constructeurs diffrent par leur signature. On est dans le cas d'un constructeur qui est une mthode surcharge un certain nombre de fois. Le compilateur ne fournit pas de constructeur par dfaut A la fin de l'excution d'un constructeur, tous les champs d'instance (donc les champs non statiques) doivent avoir t initialiss, que ce soit par le constructeur ou lors de leur dclaration. class Boisson {
Prof. M. TIMMI Page 32

public string marque; public Boisson() { marque = "no name"; }

Dans notre exemple, pour toutes les instances de la classe Boisson le champ marque est initialis "no name". On aurait donc trs bien pu crire: class Boisson { public string marque = "no name"; public Boisson() { // autres instructions } } Il est possible d'appeler un constructeur depuis un second constructeur l'aide du mot rserv this comme dans l'exemple qui suit. this(5) appelle le second constructeur, avant que le code du premier constructeur ne soit excut (vide dans notre cas).

class MaClasse { public int x; public MaClasse() : this(5) {} public MaClasse (int v) { x = v; } } MaClasse c1 = new MaClasse c2 = new Console.WriteLine Console.WriteLine Remarque: On peut spcifier n'importe quel modificateur d'accs pour les constructeurs. Dans certains cas le constructeur peut tre private afin d'interdire que la classe soit instancie. Cela peut tre souhaitable pour certaines classes d'utilitaires contenant uniquement des membres statiques, par exemple la classe System.Math. MaClasse (); MaClasse (10); (c1.x); // crit 5 (c2.x); // crit 10

Membres statiques Les champs, les proprits, les mthodes et les vnements d'une classe peuvent tre dclars avec l'attribut static. Ces membres statiques appartiennent la classe et non aux objets instancis partir de la classe. On parle galement de membres de classe, par opposition aux membres d'instance.
Prof. M. TIMMI Page 33

Les mmes rgles de visibilits sont appliques aux membres statiques. L'exemple suivant montre que l'on peut utiliser des membres statiques d'une classe sans qu'aucun objet de cette classe ne soit cr. class Robot { public static string controle = "autonome"; } ... Console.WriteLine ("Contrle: {0}", Robot.controle); Les mthodes peuvent aussi tre statiques. De telles mthodes sont alors accessibles uniquement par la classe. Considrons une classe Etudiant dans laquelle on dsire stocker le nombre d'tudiants instancis. On pourrait crire: class Etudiant { private int totalEtudiants; ... public void AfficherTotal() { Console.Writeline ("Nombre d'tudiants: " + totalEtudiants); } public void InscrireEtudiant() { TotalEtudiants = TotalEtudiants + 1; } ... } Cette manire de faire pose deux problmes: il y aura autant de fois l'information totalEtudiants qu'il y aura d'objets instancis, ce qui , outre la redondance de l'information, introduit un gaspillage de place. il est dommage d'appeler la mthode InscrireEtudiant de chaque objet, uniquement pour tenir jour le nombre total d'tudiants

Dans un premier temps on peut utiliser une variable de classe (statique) pour compter le nombre d'tudiants class Etudiant { private static int totalEtudiants; ... public void AfficherTotal() { Console.Writeline ("Nombre d'tudiants: totalEtudiants); } public void InscrireEtudiant() {
Prof. M. TIMMI Page 34

"

totalEtudiants = totalEtudiants + 1; } ... } Il est galement possible d'implmenter une proprit statique permettant d'accder totalEtudiants: class Etudiant { private static int totalEtudiants; ... public static int TotalEtudiants { get { return totalEtudiants; } set { totalEtudiants = value; } } public void InscrireEtudiant() { TotalEtudiants = TotalEtudiants + 1; } ... } La proprit statique peut tre invoque uniquement depuis la classe Etudiant: Console.WriteLine ("Nombre d'tudiants: " + Etudiant.TotalEtudiants); Si on essaie d'invoquer une proprit statique sur un objet le compilateur gnre une erreur, comme pour: Etudiant et1 = new Etudiant(); Console.WriteLine ("Nombre d'tudiants: " + et1.TotalEtudiants); Afin d'amliorer encore notre exemple, il est possible de faire appel aux mthodes statiques: class Etudiant { private static int totalEtudiants; ... public static int TotalEtudiants { get { return totalEtudiants; }
Prof. M. TIMMI Page 35

// avec 'T'

set { totalEtudiants = value; } } public static void AfficherTotal() { Console.Writeline ("Nombre d'tudiants: " + TotalEtudiants); } public static void InscrireEtudiant() { TotalEtudiants = TotalEtudiants + 1; // avec 'T' } ... } De cette manire toutes les informations et les traitements qui concerne uniquement la classe sont spcifis comme statiques. Voici un exemple d'utilisation de la classe Etudiant:

Etudiant et1 = new Etudiant(); et1.nom = "Pierre", Etudiant.InscrireEtudiant(); Etudiant et2 = new Etudiant(); Et2.nom = "Josette", Etudiant.InscrireEtudiant(); Etudiant et3 = new Etudiant(); Et3.nom = "Astrid", Etudiant.InscrireEtudiant(); Etudiant.AfficherTotal();//affiche Nombre d'tudiants: 3

Constructeurs statiques Un constructeur d'instance est utilis afin d'initialiser un objet. On peut galement spcifier un constructeur qui initialise une classe. On parle alors de constructeur statique. Un constructeur statique: a le mme nom que la classe n'a pas de paramtres est excut une seule fois peut coexister avec des constructeurs d'instances
Page 36

Prof. M. TIMMI

ne peut pas tre appel explicitement. Il est appel une fois que la premire instance de soit cre, ou avant qu'une des mthodes statiques ne soit invoque.

Hritage Lorsque l'on dveloppe une application on est souvent amen travailler avec des lments similaires, mais pas identiques. En programmation objet le principe de l'hritage permet, dans un premier temps, de dfinir une classe, puis, dans un second temps, de driver de cette classe initiale des classes plus spcifiques. La classe initiale est appele classe de base, alors que les classes construites partir de cette classe de base sont appeles classes drives. Les classes drives hritent des proprits et des mthodes de la classe de base. L'hritage permet donc de spcifier des mthodes et des proprits communes ou gnrales et de les rutiliser dans une classe drive. L'hritage prsente donc un avantage en ce qui concerne la rutilisabilit du code. Dans l'exemple qui suit on dsire travailler avec des animaux et la premire ide d'implmentation pourrait tre de crer une classe pour chaque animal: public class Chat { public bool EstEnerve; public void Mange(); public void Dort(); } public class Lion { public bool EstEnerve; public void MangeZebre(); public void Dort(); public void Rugit(); } public class Elephant { public int ChargeMaximale; public bool EstEnerve; public void Dort(); public void Mange(); } Cette structure mne une certaine duplication du code. En effet la mthode Dort est implmente plus d'une fois. D'autre part, la mthode traduisant le fait de manger ont des noms diffrents Il est plus judicieux de dfinir une structure mettant en uvre l'hritage: public class Animal {
Prof. M. TIMMI Page 37

public bool EstEnerve; public void Mange() { }; public void Dort() { Console.WriteLine ("en train de dormir..."); }; } public class Chat : Animal { } public class Lion : Animal { public void Rugit(); } public class Elephant : Animal { public int ChargeMaximale; } Les mthodes Dort et Mange sont dfinies une seule fois dans la classe de base Animal. Les trois classes drives hritent de ces mthodes: Elephant e = new Elephant(); e.Dort(); // affiche "en train de dormir..." Une classe peut hriter de n'importe quelle classe qui n'est pas dfinie avec l'attribut sealed (hritage interdit), donc galement d'une classe elle-mme drive. Reprenons notre exemple en introduisant une classe Mammifere drive de la classe Animal: public class Animal { public bool EstEnerve; public void Mange() { }; public void Dort() { Console.WriteLine ("en train de dormir..."); }; } public class Mammifere : Animal { public SousGroupe Sorte; } public class Chat : Mammifere { } public class Lion : Mammifere {
Prof. M. TIMMI Page 38

public void Rugit(); } public class Elephant : Mammifere { public int ChargeMaximale; } L'numration SousGroupe serait dfinie comme: public enum SousGroupe { Monotremes, // p.ex. ornithorynque, quidn Marsupiaux, // p.ex. kangourou, koala Placentaires // p.ex. chien, lion } On peut, par exemple, crire: Elephant e = new Elephant(); e.Dort(); e.Sorte = SousGroupe.Placentaires; Appel d'un constructeur de la classe de base Comme nous l'avons vu, lors de la cration d'un objet, un constructeur d'instance est excut. Lors de la cration d'un objet d'une classe drive: le constructeur d'instance de la classe de base est excut en premier lieu

puis le constructeur d'instance de la classe drive est excut public class Animal { public Animal() { Console.WriteLine ("Construction de Animal"); }; } public class Elephant : Animal { public Elephant() { Console.WriteLine ("Construction de Elephant"); } } Lorsqu'un objet Elephant est cr: Elephant e = new Elephant();

Prof. M. TIMMI

Page 39

Les lignes suivantes sont affiches: Construction de Animal Construction de Elephant L'ordre d'excution des constructeurs suit l'ordre de la hirarchie des classes. Dans le cas o la classe de base possde un constructeur (autre que celui par dfaut) que l'on veut appeler, il faut utiliser le mot-cl base. Si la classe de base Animal se prsente sous la forme suivante: public enum LeGenre { Male, Femelle } public class Animal { public Animal() { Console.WriteleLine ("Construction de Animal"); } Animal (LeGenre genre) { if (genre == LeGenre.Femelle) { Console.WriteleLine ("Femelle"); } else { Console.WriteleLine ("Male"); } } } Voici comment appeler comment appeler le second constructeur de la classe Animal depuis la classe drive Elephant: public class Elephant : Animal { public Elephant (LeGenre genre) : base (genre) { Console.WriteLine ("Elephant"); } } Si on cre alors un objet de type Elephant: Elephant e = new Elephant (LeGenre.Femelle); on obtient: Femelle Elephant

Prof. M. TIMMI

Page 40