Cours Csharp

  • Upload
    taleb23

  • View
    82

  • Download
    0

Embed Size (px)

Citation preview

  • 5/28/2018 Cours Csharp

    1/253

    APPRENTISSAGE DU LANGAGE C#

    Serge Tah - ISTIA - Universit d'AngersMai 2002

  • 5/28/2018 Cours Csharp

    2/253

    Introduction

    C# est un langage rcent. Il a t disponible en versions beta depuis lanne 2000 avant dtre officiellement disponible en fvrier2002 en mme temps que la plate-forme .NET de Microsoft laquelle il est li. C# ne peut fonctionner quavec cet environnementdexcution, environnement disponible pour le moment que sur les machines Windows NT, 2000 et XP.

    Avec la plate-forme .NET, trois nouveaux langages sont apparus : C#, VB.VET, JSCRIPT.NET. C# est largement une copie deJava. VB.NET et JSCRIPT.NET sont des extensions de Visual basic et Jscript pour la plate-forme .NET. Celle-ci rend disponibleaux programmes qui sexcutent en son sein un ensemble trs important de classes, classes trs proches de celles que lon trouve ausein des machines virtuelles Java. En premire approximation, on peut dire que la plate-forme .NET est un environnementdexcution analogue une machine virtuelle Java. On peut noter cependant deux diffrences importantes :

    la plate-forme .NET ne s'excute que sur les machines Windows alors que Java s'excute sur diffrents OS (windows,unix, macintosh).

    la plate-forme .NET permet l'excution de programmes crits en diffrents langages. Il suffit que le compilateur de ceux-cisache produire du code IL (Intermediate Language), code excut par la machine virtuelle .NET. Toutes les classes de.NET sont disponibles aux langages compatibles .NET ce qui tend gommer les diffrences entre langages dans la mesureo les programmes utilisent largement ces classes. Le choix d'un langage .NET devient affaire de got plus que de

    performances.De la mme faon que Java ne peut tre ignor, la plate-forme .NET ne peut l'tre, la fois cause du parc trs important demachines windows installes et de l'effort fait par Microsoft pour la promouvoir et l'imposer. I l semble que C# soit un bon choixpour dmarrer avec .NET, notamment pour les programmeurs Java, tellement ces deux langages sont proches. Ensuite on pourrapasser aisment de C# VB.NET ou un autre langage .NET. La syntaxe changera mais les classes .NET resteront les mmes.Contrairement aux apparences, le passage de VB VB.NET est difficile. VB n'est pas un langage orient objets alors que VB.NETl'est compltement. Le programmeur VB va donc tre confront des concepts qu'il ne matrise pas. Il parat plus simpled'affronter ceux-ci avec un langage entirement nouveau tel que C# plutt qu'avec VB.NET o le programmeur VB aura toujourstendance vouloir revenir ses habitudes VB.

    Ce document n'est pas un cours exhaustif. I l est destin des gens connaissant dj la programmation et qui veulent dcouvrir C#.Afin de faciliter la comparaison avec Java, il reprend la structure du document "Introduction au langage Java" du mme auteur.

    Deux livres m'ont aid :

    - Professional C# programming, Editions Wrox- C# et .NET, Grard Leblanc, Editions Eyrolles

    Ce sont deux excellents ouvrages dont je conseille la lecture.

    Serge Tah, avril 2002

  • 5/28/2018 Cours Csharp

    3/253

    1. LES BASES DU LANGAGE C# 7

    1.1 INTRODUCTION 71.2 LES DONNEES DE C# 71.2.1 LES TYPES DE DONNEES PREDEFINIS 71.2.2 CONVERSION ENTRE TYPES SIMPLES ET TYPES OBJETS 81.2.3 NOTATION DES DONNEES LITTERALES 81.2.4 DECLARATION DES DONNEES 81.2.5 LES CONVERSIONS ENTRE NOMBRES ET CHAINES DE CARACTERES 91.2.6 LES TABLEAUX DE DONNEES 101.3 LES INSTRUCTIONS ELEMENTAIRES DE C# 121.3.1 ECRITURE SUR ECRAN 121.3.2 LECTURE DE DONNEES TAPEES AU CLAVIER 131.3.3 EXEMPLE D'ENTREES-SORTIES 131.3.4 REDIRECTION DES E/S 131.3.5 AFFECTATION DE LA VALEUR D'UNE EXPRESSION A UNE VARIABLE 141.4 LES INSTRUCTIONS DE CONTROLE DU DEROULEMENT DU PROGRAMME 201.4.1 ARRET 20

    1.4.2 STRUCTURE DE CHOIX SIMPLE

    201.4.3 STRUCTURE DE CAS 211.4.4 STRUCTURE DE REPETITION 211.5 LA STRUCTURE D'UN PROGRAMME C# 241.6 COMPILATION ET EXECUTION D'UN PROGRAMME C# 241.7 L'EXEMPLE IMPOTS 241.8 ARGUMENTS DU PROGRAMME PRINCIPAL 261.9 LES ENUMERATIONS 271.10 LA GESTION DES EXCEPTIONS 281.11 PASSAGE DE PARAMETRES A UNE FONCTION 311.11.1 PASSAGE PAR VALEUR 311.11.2 PASSAGE PAR REFERENCE 311.11.3 PASSAGE PAR REFERENCE AVEC LE MOT CLE OUT 32

    2. CLASSES, STUCTURES, INTERFACES 33

    2.1 L' OBJET PAR L'EXEMPLE 332.1.1 GENERALITES 332.1.2 DEFINITION DE LA CLASSE PERSONNE 332.1.3 LA METHODE INITIALISE 342.1.4 L'OPERATEUR NEW 342.1.5 LE MOT CLE THIS 352.1.6 UN PROGRAMME DE TEST 352.1.7 UTILISER UN FICHIER DE CLASSES COMPILEES (ASSEMBLY) 362.1.8 UNE AUTRE METHODE INITIALISE 37

    2.1.9 CONSTRUCTEURS DE LA CLASSE PERSONNE 372.1.10 LES REFERENCES D'OBJETS 382.1.11 LES OBJETS TEMPORAIRES 392.1.12 METHODES DE LECTURE ET D'ECRITURE DES ATTRIBUTS PRIVES 402.1.13 LES PROPRIETES 412.1.14 LES METHODES ET ATTRIBUTS DE CLASSE 422.1.15 PASSAGE D'UN OBJET A UNE FONCTION 432.1.16 UN TABLEAU DE PERSONNES 442.2 L'HERITAGE PAR L'EXEMPLE 452.2.1 GENERALITES 452.2.2 CONSTRUCTION D'UN OBJET ENSEIGNANT 462.2.3 SURCHARGE D'UNE METHODE OU D'UNE PROPRIETE 472.2.4 LE POLYMORPHISME 49

    2.2.5 SURCHARGE ET POLYMORPHISME 492.3 REDEFIR LA SIGNIFICATION D'UN OPERATEUR POUR UNE CLASSE 522.3.1 INTRODUCTION 522.3.2 UN EXEMPLE 522.4 DEFINIR UN INDEXEUR POUR UNE CLASSE 53

  • 5/28/2018 Cours Csharp

    4/253

    2.5 LES STRUCTURES 552.6 LES INTERFACES 582.7 LES ESPACES DE NOMS 612.8 L'EXEMPLE IMPOTS 62

    3. CLASSES .NET D'USAGE COURANT 66

    3.1 CHERCHER DE L'AIDE AVEC SDK.NET 663.1.1 WINCV 663.2 CHERCHER DE L'AIDE SUR LES CLASSES AVEC VS.NET 693.2.1 HELP/CONTENTS 693.2.2 HELP/INDEX 723.3 LA CLASSE STRING 733.4 LA CLASSE ARRAY 753.5 LA CLASSE ARRAYLIST 773.6 LA CLASSE HASHTABLE 793.7 LA CLASSE STREAMREADER 813.8 LA CLASSE STREAMWRITER 823.9 LA CLASSE REGEX 833.9.1 VERIFIER QU'UNE CHAINE CORRESPOND A UN MODELE DONNE 85

    3.9.2 TROUVER TOUS LES ELEMENTS D'UNE CHAINE CORRESPONDANT A UN MODELE 863.9.3 RECUPERER DES PARTIES D'UN MODELE 873.9.4 UN PROGRAMME D'APPRENTISSAGE 883.9.5 LA METHODE SPLIT 893.10 LES CLASSES BINARYREADER ET BINARYWRITER 90

    4. INTERFACES GRAPHIQUES AVEC C# ET VS.NET 93

    4.1 LES BASES DES INTERFACES GRAPHIQUES 934.1.1 UNE FENETRE SIMPLE 934.1.2 UN FORMULAIRE AVEC BOUTON 944.2 CONSTRUIRE UNE INTERFACE GRAPHIQUE AVEC VISUAL STUDIO.NET 97

    4.2.1 CREATION INITIALE DU PROJET 974.2.2 LES FENETRE DE L'INTERFACE DE VS.NET 984.2.3 EXECUTION D'UN PROJET 1004.2.4 LE CODE GENERE PAR VS.NET 1004.2.5 CONCLUSION 1024.3 FENETRE AVEC CHAMP DE SAISIE, BOUTON ET LIBELLE 1024.3.1 LE CODE LIE A LA GESTION DES EVENEMENTS 1074.3.2 CONCLUSION 1084.4 QUELQUES COMPOSANTS UTILES 1084.4.1 FORMULAIRE FORM 1084.4.2 ETIQUETTES LABEL ET BOITES DE SAISIE TEXTBOX 1094.4.3 LISTES DEROULANTES COMBOBOX 1104.4.4 COMPOSANT LISTBOX 112

    4.4.5 CASES A COCHER CHECKBOX, BOUTONS RADIO BUTTONRADIO 1144.4.6 VARIATEURS SCROLLBAR 1154.5 VENEMENTS SOURIS 1174.6 CREER UNE FENETRE AVEC MENU 1194.7 COMPOSANTS NON VISUELS 1244.7.1 BOITES DE DIALOGUE OPENFILEDIALOG ET SAVEFILEDIALOG 1244.7.2 BOITES DE DIALOGUE FONTCOLOR ET COLORDIALOG 1294.7.3 TIMER 1314.8 L'EXEMPLE IMPOTS 133

    5. GESTION D'EVENEMENTS 136

    5.1 OBJETS DELEGATE 1365.2 GESTION D'EVENEMENTS 137

    6. ACCES AUX BASES DE DONNEES 142

  • 5/28/2018 Cours Csharp

    5/253

    6.1 GENERALITES 1426.2 LES DEUX MODES D'EXPLOITATION D'UNE SOURCE DE DONNEES 1436.3 ACCES AUX DONNEES EN MODE CONNECTE 1446.3.1 LES BASES DE DONNEES DE L'EXEMPLE 1446.3.2 UTILISATION D'UN PILOTE ODBC 1486.3.3 UTILISATION D'UN PILOTE OLE DB 1526.3.4 EXEMPLE 1 : MISE A JOUR D'UNE TABLE 1536.3.5 EXEMPLE 2 : IMPOTS 1576.4 ACCES AUX DONNEES EN MODE DECONNECTE 160

    7. LES THREADS D'EXECUTION 161

    7.1 INTRODUCTION 1617.2 CREATION DE THREADS D'EXECUTION 1627.3 INTERET DES THREADS 1647.4 ACCES A DES RESSOURCES PARTAGEES 1657.5 ACCES EXCLUSIF A UNE RESSOURCE PARTAGEE 1667.6 SYNCHRONISATION PAR EVENEMENTS 169

    8. PROGRAMMATION TCP-IP 172

    8.1 GENERALITES 1728.1.1 LES PROTOCOLES DE L'INTERNET 1728.1.2 LE MODELE OSI 1728.1.3 LE MODELE TCP/IP 1738.1.4 FONCTIONNEMENT DES PROTOCOLES DE L'INTERNET 1758.1.5 LES PROBLEMES D'ADRESSAGE DANS L'INTERNET 1768.1.6 LA COUCHE RESEAU DITE COUCHE IP DE L'INTERNET 1798.1.7 LA COUCHE TRANSPORT : LES PROTOCOLES UDP ET TCP 1808.1.8 LA COUCHE APPLICATIONS 1818.1.9 CONCLUSION 1828.2 GESTION DES ADRESSES RESEAU 182

    8.3 PROGRAMMATION TCP-IP 1858.3.1 GENERALITES 1858.3.2 LES CARACTERISTIQUES DU PROTOCOLE TCP 1858.3.3 LA RELATION CLIENT-SERVEUR 1868.3.4 ARCHITECTURE D'UN CLIENT 1868.3.5 ARCHITECTURE D'UN SERVEUR 1868.3.6 LA CLASSE TCPCLIENT 1868.3.7 LA CLASSENETWORKSTREAM 1878.3.8 ARCHITECTURE DE BASE D'UN CLIENT INTERNET 1888.3.9 LA CLASSE TCPLISTENER 1888.3.10 ARCHITECTURE DE BASE D'UN SERVEUR INTERNET 1898.4 EXEMPLES 1908.4.1 SERVEUR D'ECHO 190

    8.4.2 UN CLIENT POUR LE SERVEUR D'ECHO 1918.4.3 UN CLIENT TCP GENERIQUE 1938.4.4 UN SERVEUR TCP GENERIQUE 1988.4.5 UN CLIENT WEB 2018.4.6 CLIENT WEB GERANT LES REDIRECTIONS 2038.4.7 SERVEUR DE CALCUL D'IMPOTS 205

    9. SERVICES WEB 210

    9.1 INTRODUCTION 2109.2 UN PREMIER SERVICE WEB 2109.3 UN CLIENT HTTP-GET 216

    9.4 UN CLIENT HTTP-POST 2229.5 UN CLIENT SOAP 2269.6 ENCAPSULATION DES ECHANGES CLIENT-SERVEUR 2309.6.1 LA CLASSE D'ENCAPSULATION 2309.6.2 UN CLIENT CONSOLE 233

  • 5/28/2018 Cours Csharp

    6/253

    9.6.3 UN CLIENT GRAPHIQUE WINDOWS 2359.7 UN CLIENT PROXY 2389.8 CONFIGURER UN SERVICE WEB 2439.9 LE SERVICE WEB IMPOTS 2459.9.1 LE SERVICE WEB 2459.9.2 GENERER LE PROXY DU SERVICE IMPOTS 2509.9.3 UTILISER LE PROXY AVEC UN CLIENT 250

    10. A SUIVRE 253

  • 5/28/2018 Cours Csharp

    7/253

    Les bases de C# 7

    1. Les bases du langage C#1.1 Introduction

    Nous traitons C# d'abord comme un langage de programmation classique. Nous aborderons les objets ultrieurement. Dans unprogramme on trouve deux choses

    - des donnes- les instructions qui les manipulent

    On s'efforce gnralement de sparer les donnes des instructions :

    +--------------------+ DONNEES +-------------------- INSTRUCTIONS

    +--------------------+

    1.2 Les donnes de C#

    C# utilise les types de donnes suivants:

    1. les nombres entiers2. les nombres rels3. les nombres dcimaux4. les caractres et chanes de caractres5. les boolens

    6. les objets

    1.2.1 Les types de donnes prdfinis

    Type Codage Domainechar 2 octets caractre Unicodeint 4 octets [-231, 231-1] [2147483648, 2147483647]uint 4 octets [0, 232-1] [0, 4294967295]long 8 octets [-263, 263-1] [9223372036854775808, 9223372036854775807]ulong 8 octets [0, 264-1] [0, 18446744073709551615]sbyte 1 octet [-27, 27-1] [-128,+127]

    byte 1 octet [0 , 28-1] [0,255]short 2 octets [-215, 215-1] [-32768, 32767]ushort 2 octets [0, 216-1] [0,65535]float 4 octets [1.5 10-45, 3.4 10+38] en valeur absoluedouble 8 octets [5.0 10-324, 1.7 10+308] en valeur absoluedecimal 16 octets [1.0 10-28,7.9 10+28] en valeur absolue avec 28 chiffres significatifsbool 1 bit true, falseChar rfrence d'objet charString rfrence d'objet chane de caractres

    DateTime rfrence d'objet date et heureInt32 rfrence d'objet intInt64 rfrence d'objet longByte rfrence d'objet byte

    Float rfrence d'objet floatDouble rfrence d'objet doubleDecimal rfrence d'objet decimalBoolean rfrence d'objet boolean

  • 5/28/2018 Cours Csharp

    8/253

    Les bases de C# 8

    1.2.2 Conversion entre types simples et types objets

    Dans le tableau ci-dessus, on dcouvre qu'il y a deux types possibles pour un entier sur 32 bits :intet Int32. Le type int est un typesimple dont on ne manipule que la valeur. Int32est une classe. Un objet de ce type est complexe et possde des attributs etmthodes. C# est amen faire des conversion implicites entre ces deux types. Ainsi si une fonction attend comme paramtre unobjet de type Int32, on pourra lui passer une donne de type int. Le compilateur fera implicitement la conversion int-->Int32. On

    appelle cela le "boxing" c.a.d. littralement la mise en bote d'une valeur dans un objet. L'inverse est galement vrai. L o unefonction attend une valeur de type int, on pourra lui passer une donne de type Int32. La conversion se fera l encoreautomatiquement et s'appelle le "unboxing". Les oprations implicites de boxing/unboxing se font sur les types suivants :

    int Int32long Int64decimal Decimalbool Booleanchar Charbyte Bytefloat Floatdouble Doubleenum Enum

    1.2.3 Notation des donnes littrales

    entier int (32 bits) 145, -7, 0xFF (hexadcimal)entier long (64 bits) 100000Lrel double 134.789, -45E-18 (-45 10-18)rel float 134.789F, -45E-18F(-45 10-18)rel decimal 100000Mcaractre char 'A', 'b'chane de caractres string "aujourd'hui" "c:\ \ chap1\ \ paragraph3" @"c:\ chap1\ paragraph3"boolen bool true, false

    date new DateTime(1954,10,13) (an, mois, jour) pour le 13/10/ 1954On notera les deux chanes littrales : "c:\ \ chap1\ \ paragraph3"et@" c:\ chap1\ paragraph3". Dans les chanes littrales, le caractre \ est interprt. Ainsi " \ n"reprsente la marque de fin de ligne et non la succession des deux caractres \ et n. Si on voulait cettesuccession, il faudrait crire"\ \ n"o la squence\ \ est remplace par un seul \ non interprt. On pourrait crire aussi@"\n"pour avoir le mme rsultat. La syntaxe@" texte"demande que textesoit pris exactement comme il est crit. On appelle parfois celaune chaneverbatim.

    1.2.4 Dclaration des donnes

    1.2.4.1 Rle des dclarations

    Un programme manipule des donnes caractrises par un nom et un type. Ces donnes sont stockes en mmoire. Au moment dela traduction du programme, le compilateur affecte chaque donne un emplacement en mmoire caractris par une adresse etune taille. I l le fait en s'aidant des dclarations faites par le programmeur.Par ailleurs celles-ci permettent au compilateur de dtecter des erreurs de programmation. Ainsi l'opration

    x=x*2;sera dclare errone si x est une chane de caractres par exemple.

    1.2.4.2 Dclaration des constantes

    La syntaxe de dclaration d'une constante est la suivante :

    consttype nom=valeur; / / dfinit constante nom=valeurex : constfloat PI=3.141592F;

  • 5/28/2018 Cours Csharp

    9/253

    Les bases de C# 9

    Pourquoi dclarer des constantes ?

    1. La lecture du programme sera plus aise si l'on a donn la constante un nom significatif :

    ex :constfloat taux_tva= 0.186F;

    2. La modification du programme sera plus aise si la "constante" vient changer. Ainsi dans le cas prcdent, si le taux de tvapasse 33%, la seule modification faire sera de modifier l'instruction dfinissant sa valeur :

    finalfloat taux_tva=0.33F;

    Si l'on avait utilis 0.186 explicitement dans le programme, ce serait alors de nombreuses instructions qu'il faudrait modifier.

    1.2.4.3 Dclaration des variables

    Une variable est identifie par un nom et se rapporte un type de donnes. C# fait la diffrence entre majuscules et minuscules.Ainsi les variablesFINet finsont diffrentes.

    Les variables peuvent tre initialises lors de leur dclaration. La syntaxe de dclaration d'une ou plusieurs variables est :identificateur_de_type variable1,variable2,...,variablen;

    o identificateur_de_typeest un type prdfini ou bien un type dfini par le programmeur.

    1.2.5 Les conversions entre nombres et chanes de caractres

    nombre -> chane " " + nombrechaine -> int int.Parse(chaine) ou I nt32.Parsechane -> long long.Parse(chaine) pu Int64.Parsechane -> double double.Parse(chane) ou Double.Parse(chane)chane -> float float.Parse(chane) ou Float.Parse(chane)

    La conversion d'une chane vers un nombre peut chouer si la chane ne reprsente pas un nombre valide. Il y a alors gnrationd'une erreur fatale appeleexceptionen C#. Cette erreur peut tre gre par la clausetry/ catchsuivante :

    try{appel de la fonction susceptible de gnrer l'exception

    } catch (Exception e){traiter l'exception e

    }instruction suivante

    Si la fonction ne gnre pas d'exception, on passe alors instruction suivante, sinon on passe dans le corps de la clausecatchpuis instruction suivante. Nous reviendrons ultrieurement sur la gestion des exceptions. Voici un programme prsentant lesprincipales techniques de conversion entre nombres et chanes de caractres. Dans cet exemple la fonction affiche crit l'cran lavaleur de son paramtre. Ainsiaffiche(S)crit la valeur de S l'cran.

    // espaces de noms importsusingSystem;

    // la classe de testpublicclassconv1{

    publicstaticvoidMain(){

    String S;constinti=10;constlongl=100000;constfloatf=45.78F;doubled=-14.98;

    // nombre --> chane

    S=""+i;affiche(S);S=""+l;affiche(S);S=""+f;affiche(S);

  • 5/28/2018 Cours Csharp

    10/253

    Les bases de C# 10

    S=""+d;affiche(S);

    //boolean --> chaneconstboolb=false;S=""+b;affiche(S);

    // chane --> intinti1;i1=int.Parse("10");affiche(""+i1);try{i1=int.Parse("10.67");affiche(""+i1);

    } catch(Exception e){affiche("Erreur "+e.Message);

    }

    // chane --> longlongl1;l1=long.Parse("100");affiche(""+l1);try{l1=long.Parse("10.675");affiche(""+l1);

    } catch(Exception e){affiche("Erreur "+e.Message);

    }

    // chane --> double

    doubled1;d1=double.Parse("100,87");affiche(""+d1);try{d1=double.Parse("abcd");affiche(""+d1);

    } catch(Exception e){affiche("Erreur "+e.Message);

    }

    // chane --> floatfloatf1;f1=float.Parse("100,87");affiche(""+f1);try{d1=float.Parse("abcd");affiche(""+f1);

    } catch(Exception e){affiche("Erreur "+e.Message);

    }

    }// fin main

    publicstaticvoidaffiche(String S){Console.Out.WriteLine("S="+S);

    }}// fin classe

    Les rsultats obtenus sont les suivants :

    S=10S=100000S=45.78S=-14.98

    S=FalseS=10S=Erreur The input string was not in a correct format.S=100S=Erreur The input string was not in a correct format.S=100.87S=Erreur The input string was not in a correct format.S=100.87S=Erreur The input string was not in a correct format.

    On remarquera que les nombres rels sous forme de chane de caractres doivent utiliser la virgule et non le point dcimal. Ainsi oncrira

    double d1=10.7; maisdouble d2=int.Parse("10,7");

    1.2.6 Les tableaux de donnes

  • 5/28/2018 Cours Csharp

    11/253

    Les bases de C# 11

    Un tableau C# est un objet permettant de rassembler sous un mme identificateur des donnes de mme type. Sa dclaration est lasuivante :

    Type[] Tableau[]= new Type[n]

    nest le nombre de donnes que peut contenir le tableau. La syntaxeTableau[i]dsigne la donne n io i appartient l'intervalle[0,n-1]. Toute rfrence la donneTableau[i]o in'appartient pas l'intervalle [0,n-1]provoquera une exception. Un tableau peuttre initialis en mme temps que dclar :

    int[] entiers=new int[] {0,10,20,30};

    Les tableaux ont une propritLengthqui est le nombre d'lments du tableau. Un tableau deux dimensions pourra tre dclarcomme suit :

    Type[,] Tableau=new Type[n,m];

    onest le nombre de lignes,mle nombre de colonnes. La syntaxeTableau[i,j]dsigne l'lment j de la ligne i de Tableau. Le tableau deux dimensions peut lui aussi tre initialis en mme temps qu'il est dclar :

    double[,] rels=new double[,] { {0.5, 1.7}, {8.4, -6}};

    Le nombre d'lments dans chacune des dimensions peut tre obtenue par la mthodeGetLenth(i)o i=0 reprsente la dimensioncorrespondant au 1er indice, i=1 la dimension correspondant au 2ime indice, Un tableau de tableaux est dclar comme suit :

    Type[][] Tableau=new Type[n][ ];

    La dclaration ci-dessus cre un tableau denlignes. Chaque lmentTableau[i]est une rfrence de tableau une dimension. Cestableaux ne sont pas crs lors de la dclaration ci-dessus. L'exemple ci-dessous illustre la cration d'un tableau de tableaux :

    // un tableau de tableauxstring[][] noms=new string[3][];for(inti=0;i

  • 5/28/2018 Cours Csharp

    12/253

    Les bases de C# 12

    Console.Out.WriteLine("noms["+i+"]["+j+"]="+noms[i][j]);}//for j

    }//for i

    }//Main}//class

    A l'excution, nous obtenons les rsultats suivants :

    entiers[0]=0

    entiers[1]=10entiers[2]=20entiers[3]=30rels[0,0]=0.5rels[0,1]=1.7rels[1,0]=8.4rels[1,1]=-6noms[0][0]=nom00noms[1][0]=nom10noms[1][1]=nom11noms[2][0]=nom20noms[2][1]=nom21noms[2][2]=nom22

    1.3 Les instructions lmentaires de C#On distingue

    1 les instructions lmentaires excutes par l'ordinateur.2 les instructions de contrle du droulement du programme.

    Les instructions lmentaires apparaissent clairement lorsqu'on considre la structure d'un micro-ordinateur et de ses priphriques.

    U. C MEMOIRE ECRAN+-------------------+ +-------+ 2 3

    +-----------+ 1 ----+------+->

    CLAVIER +-----------+--------+--> +-----------+ +-------------------+ +-------+

    4^\\ 5 +-------+\ ---->

    DISQUE+-------+

    1. lecture d'informations provenant du clavier2. traitement d'informations3. criture d'informations l'cran4. lecture d'informations provenant d'un fichier disque5. criture d'informations dans un fichier disque

    1.3.1 Ecriture sur cran

    Il existe diffrentes instructions d'criture l'cran :

    Console.Out.WriteL ine(expression)Console.Wri teL ine(expression)Console.E rror.WriteL ine (expression)

    o expressionest tout type de donne qui puisse tre converti en chane de caractres pour tre affich l'cran. Dans les exemplesvus jusqu'ici, nous n'avons utilis que l'instructionConsole.Out.Wri teL ine(expression).

    La classeSystem.Consoledonne accs aux oprations d'criture cran (Write, WriteLine). La classeConsolea deux propritsOutetErrorqui sont desflux d'criturede typeStreamWriter:

    Console.WriteL ine()est quivalent Console.Out.Wri teL ine()et crit sur le fluxOutassoci habituellement l'cran.

  • 5/28/2018 Cours Csharp

    13/253

    Les bases de C# 13

    Console.Error.Wri teL ine()crit sur le fluxError, habituellement associ lui aussi l'cran.

    Les fluxOutetErrorsont associs par dfaut l'cran. Mais ils peuvent tre redirigs vers des fichiers texte au moment de l'excutiondu programme comme nous le verrons prochainement.

    1.3.2 Lecture de donnes tapes au clavier

    Le flux de donnes provenant du clavier est dsign par l'objetConsole.I nde typeStreamReader. Ce type d'objets permet de lire une

    ligne de texte avec la mthodeReadL ine:

    String ligne=Console.In.readLine();

    La ligne tape au clavier est range dans la variableligneet peut ensuite tre exploite par le programme.Le fluxInpeut tre redirigvers un fichier comme les fluxOutetError.

    1.3.3 Exemple d'entres-sorties

    Voici un court programme d'illustration des oprations d'entres-sorties clavier/ cran :

    usingSystem;

    public class io1{publicstaticvoidMain (){

    // criture sur le flux Outobjectobj=newobject();Console.Out.WriteLine(""+obj);

    // criture sur le flux Errorinti=10;Console.Error.WriteLine("i="+i);

    // lecture d'une ligne saisie au clavierConsole.Out.Write("Tapez une ligne : ");string ligne=Console.In.ReadLine();Console.Out.WriteLine("ligne="+ligne);

    }//fin main}//fin classe

    et les rsultats de l'excution :

    System.Objecti=10Tapez une ligne : je suis lligne=je suis l

    Les instructions

    object obj=new object();Console.Out.WriteLine(""+obj);

    ont pour but de montrer que n'importe quel objet peut faire l'objet d'un affichage. Nous ne chercherons pas ici expliquer la

    signification de ce qui est affich.

    1.3.4 Redirection des E/ S

    Il existe sous DOS et UNIX trois priphriques stadard appels :

    1. priphrique d'entre standard - dsigne par dfaut le clavier et porte le n 02. priphrique de sortie standard - dsigne par dfaut l'cran et porte le n 13. priphrique d'erreur standard - dsigne par dfaut l'cran et porte le n 2

    En C#, le flux d'critureConsole.Outcrit sur le priphrique 1, le flux d'critureConsole.E rrorcrit sur le priphrique 2 et le flux delectureConsole.I nlit les donnes provenant du priphrique 0.

    Lorsqu'on lance un programme sous Dos ou Unix, on peut fixer quels seront les priphriques 0, 1 et 2 pour le programmeexcut. Considrons la ligne de commande suivante :

  • 5/28/2018 Cours Csharp

    14/253

    Les bases de C# 14

    pg arg1 arg2 .. argn

    Derrire les argumentsargidu programmepg, on peut rediriger les priphriques d'E/ S standard vers des fichiers:

    0console2testcriture dans flux Out : testcriture dans flux Error : test

    L'excution prcdente ne redirige aucun des flux d'E/ S standardIn, Out, Error. Nos allons maintenant rediriger les trois flux. Leflux Insera redirig vers un fichier in.txt, le fluxOutvers le fichier out.txt, le fluxErrorvers le fichiererror.txt. Cette redirection a lieusur la ligne de commande sous la forme

    E:\data\serge\MSNET\c#\bases\1>console2 0out.txt 2>error.txt

    L'excution donne les rsultats suivants :

    E:\data\serge\MSNET\c#\bases\1>more in.txttest

    E:\data\serge\MSNET\c#\bases\1>console2 0out.txt 2>error.txt

    E:\data\serge\MSNET\c#\bases\1>more out.txtcriture dans flux Out : test

    E:\data\serge\MSNET\c#\bases\1>more error.txtcriture dans flux Error : test

    On voit clairement que les fluxOutet Inn'crivent pas sur les mmes priphriques.

    1.3.5 Affectation de la valeur d'une expression une variable

    On s'intresse ici l'opration variable=expression;

    L'expression peut tre de type : arithmtique, relationnelle, boolenne, caractres

    1.3.5.1 Interprtation de l'opration d'affectation

  • 5/28/2018 Cours Csharp

    15/253

    Les bases de C# 15

    L'opration variable=expression;

    est elle-mme uneexpressiondont l'valuation se droule de la faon suivante :

    La partie droite de l'affectation est value : le rsultat est une valeur V. la valeur V est affecte la variable la valeur V est aussi la valeur de l'affectation vue cette fois en tant qu'expression.

    C'est ainsi que l'opration

    V 1= V 2= expression

    est lgale. A cause de la priorit, c'est l'oprateur = le plus droite qui va tre valu. On a doncV 1= (V 2=expression)

    L'expression V 2= expressionest value et a pour valeur V. L'valuation de cette expression a provoqu l'affectation de V V2.L'oprateur = suivant est alors valu sous la forme :

    V 1=V

    La valeur de cette expression est encore V. Son valuation provoque l'affectation de V V1.

    Ainsi donc, l'opration V 1= V 2= expression

    est une expression dont l'valuation

    1 provoque l'affectation de la valeur deexpressionaux variables V1 et V22 rend comme rsultat la valeur deexpression.

    On peut gnraliser une expression du type :

    V 1= V 2= ....=V n=expression

    1.3.5.2 Expression arithmtique

    Les oprateurs des expressions arithmtiques sont les suivants :

    + addition- soustraction* multiplication/ division : le rsultat est le quotient exact si l'un au moins des oprandes est rel. Si les deux oprandes sont entiers le

    rsultat estle quotient entier. Ainsi 5/2 -> 2 et 5.0/2 ->2.5.% division : le rsultat est le reste quelque soit la nature des oprandes, le quotient tant lui entier. C'est donc l'opration

    modulo.

    Il existe diverses fonctions mathmatiques. En voici quelques-unes :

    double Sqrt(double x) racine carredouble Cos(double x) Cosinusdouble Sin(double x) Sinusdouble Tan(double x) Tangente

    double Pow(double x,double y) x la puissance y (x>0)double Exp(double x) Exponentielledouble Log(double x) Logarithme npriendouble Abs(double x) valeur absolue

    etc...

    Toutes ces fonctions sont dfinies dans une classe C# appeleMath. Lorsqu'on les utilise, il faut les prfixer avec le nom de laclasse o elles sont dfinies. Ainsi on crira :

  • 5/28/2018 Cours Csharp

    16/253

    Les bases de C# 16

    double x, y=4;x= Math.Sqrt(y);

    La dfinition complte de la classeMathest la suivante :

    // from module 'c:\winnt\microsoft.net\framework\v1.0.2914\mscorlib.dll'public sealed class Math :

    object{

    // Fieldspublic static const doubleE;public static const doublePI;

    // Constructors

    // Methodspublic static longAbs(longvalue);public static intAbs(intvalue);public static shortAbs(shortvalue);public static SByte Abs(SByte value);public static doubleAbs(doublevalue);public static Decimal Abs(Decimal value);public static floatAbs(floatvalue);public static doubleAcos(doubled);public static doubleAsin(doubled);public static doubleAtan(doubled);public static doubleAtan2(doubley, doublex);public static doubleCeiling(doublea);

    public static doubleCos(doubled);public static doubleCosh(doublevalue);public virtual boolEquals(objectobj);public static doubleExp(doubled);public static doubleFloor(doubled);public virtual intGetHashCode();public Type GetType();public static doubleIEEERemainder(doublex, doubley);public static doubleLog(doublea, doublenewBase);public static doubleLog(doubled);public static doubleLog10(doubled);public static Decimal Max(Decimal val1, Decimal val2);public static byteMax(byteval1, byteval2);public static shortMax(shortval1, shortval2);public static UInt32 Max(UInt32 val1, UInt32 val2);public static UInt64 Max(UInt64 val1, UInt64 val2);public static longMax(longval1, longval2);public static intMax(intval1, intval2);

    public static doubleMax(doubleval1, doubleval2);public static floatMax(floatval1, floatval2);public static UInt16 Max(UInt16 val1, UInt16 val2);public static SByte Max(SByte val1, SByte val2);public static intMin(intval1, intval2);public static UInt32 Min(UInt32 val1, UInt32 val2);public static shortMin(shortval1, shortval2);public static UInt16 Min(UInt16 val1, UInt16 val2);public static longMin(longval1, longval2);public static doubleMin(doubleval1, doubleval2);public static Decimal Min(Decimal val1, Decimal val2);public static UInt64 Min(UInt64 val1, UInt64 val2);public static floatMin(floatval1, floatval2);public static byteMin(byteval1, byteval2);public static SByte Min(SByte val1, SByte val2);public static doublePow(doublex, doubley);public static doubleRound(doublea);public static Decimal Round(Decimal d);public static Decimal Round(Decimal d, intdecimals);

    public static doubleRound(doublevalue, intdigits);public static intSign(SByte value);public static intSign(shortvalue);public static intSign(intvalue);public static intSign(longvalue);public static intSign(Decimal value);public static intSign(doublevalue);public static intSign(floatvalue);public static doubleSin(doublea);public static doubleSinh(doublevalue);public static doubleSqrt(doubled);public static doubleTan(doublea);public static doubleTanh(doublevalue);public virtual stringToString();

    } // end of System.Math

    1.3.5.3 Priorits dans l'valuation des expressions arithmtiques

    La priorit des oprateurs lors de l'valuation d'une expression arithmtique est la suivante (du plus prioritaire au moins prioritaire) :

  • 5/28/2018 Cours Csharp

    17/253

    Les bases de C# 17

    [fonctions], [ ( )],[ * , / , %], [+ , -]

    Les oprateurs d'un mme bloc [ ] ont mme priorit.

    1.3.5.4 Expressions relationnelles

    Les oprateurs sont les suivants :=

    priorits des oprateurs1. >, >=,

  • 5/28/2018 Cours Csharp

    18/253

    Les bases de C# 18

    -1 si chane n1 < chane n2

    La variableegalaura la valeur truesi les deux chanes sont gales.

    1.3.5.5 Expressions boolennes

    Les oprateurs utilisables sont AND (& &) OR(| |) NOT (!). Le rsultat d'une expression boolenne est un boolen.

    priorits des oprateurs :1. !2. &&3. ||

    int fin;int x;fin= x>2 && x>4 0xFF12 le bit de signe est prserv.i& j 0x1023i| j 0xF33F~ i 0xEDC0

    1.3.5.7 Combinaison d'oprateurs

    a=a+b peut s'crire a+=ba=a-b peut s'crire a-=b

    Il en est de mme avec les oprateurs/ , %,* ,> , & , | , . Ainsi a=a+2;peut s'crirea+=2;

    1.3.5.8 Oprateurs d' incrmentation et de dcrmentation

    La notation variable++signifie variable= variable+1ou encorevariable+=1La notation variable--signifie variable= variable-1ou encorevariable-= 1.

  • 5/28/2018 Cours Csharp

    19/253

    Les bases de C# 19

    1.3.5.9 L 'oprateur ?

    L'expression

    expr_cond ? expr1:expr2

    est value de la faon suivante :

    1 l'expressionexpr_condest value. C'est une expression conditionnelle valeur vrai ou faux2 Si elle est vraie, la valeur de l'expression est celle deexpr1. expr2n'est pas value.3 Si elle est fausse, c'est l'inverse qui se produit : la valeur de l'expression est celle deexpr2.expr1n'est pas value.

    L'opration i= (j>4 ? j+1:j-1); affectera la variable i :j+1sij> 4,j-1sinon. C'est la mme chose que d'crire if(j>4) i= j+ 1; else i= j-1;mais c'est plus concis.

    1.3.5.10 Prioritgnrale des oprateurs

    () [] fonction gd

    ! ~ ++ -- dg

    new (type) oprateurs cast dg* / % gd

    + - gd

    > gd

    < >= instanceof gd

    == != gd

    & gd

    ^ gd

    | gd

    && gd

    || gd

    ? : dg

    = += -= etc. . dg

    gd indique qu'a priorit gale, c'est la priorit gauche-droite qui est observe. Cela signifie que lorsque dans une expression, l'on ades oprateurs de mme priorit, c'est l'oprateur le plus gauche dans l'expression qui est valu en premier.dg indique unepriorit droite-gauche.

    1.3.5.11 Les changements de type

    Il est possible, dans une expression, de changer momentanment le codage d'une valeur. On appelle cela changer le type d'unedonne ou en anglaistype casting. La syntaxe du changement du type d'une valeur dans une expression est la suivante:

    (type) valeur

    La valeur prend alors le type indiqu. Cela entrane un changement de codage de la valeur.

    int i, j;float isurj;isurj= (float)i/j; // priorit de () sur /

    Ici il est ncessaire de changer le type deioujen rel sinon la division donnera le quotient entier et non rel. iest une valeur code de faon exacte sur 2 octets (float) iest la mme valeur code de faon approche en rel sur 4 octets

    Il y a donc transcodage de la valeur dei. Ce transcodage n'a lieu que le temps d'un calcul, la variable iconservant toujours son typeint.

  • 5/28/2018 Cours Csharp

    20/253

    Les bases de C# 20

    1.4 Les instructions de contrle du droulement du programme

    1.4.1 Arrt

    La mthode Exitdfinie dans la classeEnvironmentpermet d'arrter l'excution d'un programme.

    syntaxe void Exit(int status)

    action arrte le processus en cours et rend la valeurstatusau processus pre

    exitprovoque la fin du processus en cours et rend la main au processus appelant. La valeur destatuspeut tre utilise par celui-ci.Sous DOS, cette variable status est rendue DOS dans la variable systmeERRORLEVELdont la valeur peut tre teste dans unfichier batch. Sous Unix, c'est la variable$?qui rcupre la valeur destatus.

    Environment.Exit(0);

    arrtera l'excution du programme avec une valeur d'tat 0.

    1.4.2 Structure de choix simple

    syntaxe : if (condition) { actions_condition_vraie;} else { actions_condition_fausse;}

    notes:

    la condition est entoure de parenthses. chaque action est termine par point-virgule. les accolades ne sont pas termines par point-virgule. les accolades ne sont ncessaires que s'il y a plus d'une action. la clauseelsepeut tre absente. Il n'y a pas de clausethen.

    L'quivalent algorithmique de cette structure est la structuresi .. alors sinon:

    si conditionalors actions_condition_vraiesinon actions_condition_fausse

    finsi

    exemple

    ifififif(x>0) { nx=nx+1;sx=sx+x;} elseelseelseelsedx=dx-x;

    On peut imbriquer les structures de choix :

    if(condition1)if (condition2){......}else //condition2{......}

    else //condition1{.......}

    Se pose parfois le problme suivant :

    public static voidMain(){intn=5;

    if(n>1)if(n>6)

    Console.Out.WriteLine(">6");else Console.Out.WriteLine ("

  • 5/28/2018 Cours Csharp

    21/253

    Les bases de C# 21

    public static voidMain(){ intn=0;

    if(n>1)if(n>6) Console.Out.WriteLine (">6");else; // else du if(n>6) : rien faire

    else Console.Out.WriteLine ("

  • 5/28/2018 Cours Csharp

    22/253

    Les bases de C# 22

    Structure for

    La syntaxe est la suivante :

    forforforfor(i=id;i

  • 5/28/2018 Cours Csharp

    23/253

    Les bases de C# 23

    actions;}

    On boucle tant que la condition est vrifie. La boucle peut ne jamais tre excute.

    notes:

    la condition est entoure de parenthses. chaque action est termine par point-virgule. l'accolade n'est ncessaire que s'il y a plus d'une action. l'accolade n'est pas suivie de point-virgule.

    La structure algorithmique correspondante est la structure tantque :

    tantque conditionactions

    fintantque

    Structure rpter jusqu' (do while)

    La syntaxe est la suivante :

    dodododo{instructions;

    }whilewhilewhilewhile(condition);

    On boucle jusqu' ce que la condition devienne fausse ou tant que la condition est vraie. Ici la boucle est faite au moins une fois.

    notes

    la condition est entoure de parenthses. chaque action est termine par point-virgule. l'accolade n'est ncessaire que s'il y a plus d'une action. l'accolade n'est pas suivie de point-virgule.

    La structure algorithmique correspondante est la structurerpter jusqu':

    rpteractions

    jusqu' condition

    Structure pour gnrale (for)

    La syntaxe est la suivante :

    forforforfor(instructions_dpart;condition;instructions_fin_boucle){instructions;

    }

    On boucle tant que la condition est vraie (value avant chaque tour de boucle). Instructions_dpartsont effectues avant d'entrerdans la boucle pour la premire fois. Instructions_fin_bouclesont excutes aprs chaque tour de boucle.

    notes

    les diffrentes instructions dans instructions_departet instructions_fin_bouclesont spares par des virgules.

    La structure algorithmique correspondante est la suivante :

    instructions_dparttantque condition

    actionsinstructions_fin_bouclefintantque

  • 5/28/2018 Cours Csharp

    24/253

    Les bases de C# 24

    Exemples

    Les programmes suivants calculent tous la somme des n premiers nombres entiers.

    1 forforforfor(i=1, somme=0;i

  • 5/28/2018 Cours Csharp

    25/253

    Les bases de C# 25

    on calcule le nombre de parts du salari nbParts=nbEnfants/2 +1s'il n'est pas mari, nbEnfants/ 2+2s'il est mari, onbEnfantsest son nombre d'enfants.

    s'il a au moins trois enfants, il a une demi-part de plus on calcule son revenu imposableR=0.72*So S est son salaire annuel on calcule son coefficient familialQF=R/ nbParts on calcule son impt I. Considrons le tableau suivant :

    12620.0 0 013190 0.05 631

    15640 0.1 1290.5

    24740 0.15 2072.531810 0.2 3309.5

    39970 0.25 4900

    48360 0.3 6898.555790 0.35 9316.5

    92970 0.4 12106

    127860 0.45 16754.5151250 0.50 23147.5

    172040 0.55 30710

    195000 0.60 393120 0.65 49062

    Chaque ligne a 3 champs. Pour calculer l'impt I , on recherche la premire ligne oQF< =champ1. Par exemple, si QF=23000 ontrouvera la ligne

    24740 0.15 2072.5L'impt I est alors gal 0.15*R - 2072.5*nbParts. Si QF est tel que la relationQF=0) OK=true;elseConsole.Error.WriteLine("Rponse incorrecte. Recommencez");

    } catch(Exception){Console.Error.WriteLine("Rponse incorrecte. Recommencez");

    }// try}// while

    // salaireOK=false;intSalaire=0;while(! OK){Console.Out.Write("Salaire annuel : ");reponse=Console.In.ReadLine();try{Salaire=int.Parse(reponse);if(Salaire>=0) OK=true;elseConsole.Error.WriteLine("Rponse incorrecte. Recommencez");

  • 5/28/2018 Cours Csharp

    26/253

    Les bases de C# 26

    } catch(Exception){Console.Error.WriteLine("Rponse incorrecte. Recommencez");

    }// try}// while

    // calcul du nombre de partsdecimalNbParts;if(Marie) NbParts=(decimal)NbEnfants/2+2;elseNbParts=(decimal)NbEnfants/2+1;

    if(NbEnfants>=3) NbParts+=0.5M;

    // revenu imposabledecimalRevenu;Revenu=0.72M*Salaire;

    // quotient familialdecimalQF;QF=Revenu/NbParts;

    // recherche de la tranche d'impots correspondant QFinti;intNbTranches=Limites.Length;Limites[NbTranches-1]=QF;i=0;while(QF>Limites[i]) i++;// l'impt

    intimpots=(int)(i*0.05M*Revenu-CoeffN[i]*NbParts);

    // on affiche le rsultatConsole.Out.WriteLine("Impt payer : " + impots);

    }// main

    }// classe

    Le programme est compil dans une fentre Dos par :

    E:\data\serge\MSNET\c#\impots\4>C:\WINNT\Microsoft.NET\Framework\v1.0.2914\csc.exe impots.csMicrosoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

    La compilation produit un excutable impots.exe:

    E:\data\serge\MSNET\c#\impots\4>dir30/04/2002 16:16 2 274 impots.cs30/04/2002 16:16 5 120 impots.exe

    Il faut noter que impots.exe n'est pas directement excutable par le processeur mais uniquement. Il contient en ralit du codeintermdiaire qui n'est excutable que sur une plate-forme .NET. Les rsultats obtenus sont les suivants :

    E:\data\serge\MSNET\c#\impots\4>impotsEtes-vous mari(e) (O/N) ? oNombre d'enfants : 3Salaire annuel : 200000Impt payer : 16400

    E:\data\serge\MSNET\c#\impots\4>impotsEtes-vous mari(e) (O/N) ? nNombre d'enfants : 2Salaire annuel : 200000Impt payer : 33388

    E:\data\serge\MSNET\c#\impots\4>impotsEtes-vous mari(e) (O/N) ? wRponse incorrecte. RecommencezEtes-vous mari(e) (O/N) ? qRponse incorrecte. RecommencezEtes-vous mari(e) (O/N) ? oNombre d'enfants : qRponse incorrecte. RecommencezNombre d'enfants : 2Salaire annuel : qRponse incorrecte. RecommencezSalaire annuel : 1Impt payer : 0

    1.8 Arguments du programme principal

  • 5/28/2018 Cours Csharp

    27/253

    Les bases de C# 27

    La fonction principale Mainpeut admettre comme paramtre un tableau de chanes :String[] (ou string[]). Ce tableau contient lesarguments de la ligne de commande utilise pour lancer l'application. Ainsi si on lance le programme P avec la commande :

    P arg0 arg1 argn

    et si la fonctionMainest dclare comme suit :

    public static void main(String[] arg);

    on aura arg[0]="arg0", arg[1]="arg1" Voici un exemple :

    // importsusingSystem;

    publicclassarg1{publicstaticvoidMain(String[] args){// on liste les paramtresConsole.Out.WriteLine("Il y a " + args.Length + " arguments");for(inti=0;i

  • 5/28/2018 Cours Csharp

    28/253

    Les bases de C# 28

    Console.Out.WriteLine(m);}//foreach

    De la mme faon que le type simple intest quivalent la classe Int32, le type simpleenumest quivalent la classeEnum. Cetteclasse a une mthode statiqueGetV aluesqui permet d'obtenir toutes les valeurs d'un type numr que l'on passe en paramtre.Celui-ci doit tre un objet de type Typequi est une classe d'information sur le type d'une donne. Le type d'une variable vestobtenu par v.GetType(). Donc ici maMention.GetType() donne l'objet Type de l'numration mentions etEnum.GetV alues(maMention.GetType())la liste des valeurs de l'numrationmentions.

    Si on crit maintenant

    foreach(intm in Enum.GetValues(maMention.GetType())){Console.Out.WriteLine(m);

    }//foreach

    on obtiendra la liste des valeurs de l'numration sous forme d'entiers. C'est ce que montre le programme suivant :

    // numration

    usingSystem;

    publicclassintro{// une numrationenummention {Passable,AssezBien,Bien,TrsBien, Excellent};publicstaticvoidMain(){

    // une variable qui prend ses valeurs dans l'numration mentionsmention maMention=mention.Passable;// affichage valeur variableConsole.Out.WriteLine("mention="+maMention);// test avec valeur de l'numrationif(maMention==mention.Passable){Console.Out.WriteLine("Peut mieux faire");

    }//if// liste des mentionsforeach(mention m in Enum.GetValues(maMention.GetType())){Console.Out.WriteLine(m);

    }//foreachforeach(intm in Enum.GetValues(maMention.GetType())){Console.Out.WriteLine(m);

    }//foreach}//Main

    }//classe

    Les rsultats d'excution sont les suivants :mention=PassablePeut mieux fairePassableAssezBienBienTrsBien0123

    1.10 La gestion des exceptionsDe nombreuses fonctions C# sont susceptibles de gnrer des exceptions, c'est dire des erreurs. Lorsqu'une fonction estsusceptible de gnrer une exception, le programmeur devrait la grer dans le but d'obtenir des programmes plus rsistants auxerreurs : il faut toujours viter le "plantage" sauvage d'une application.

    La gestion d'une exception se fait selon le schma suivant :

    try{appel de la fonction susceptible de gnrer l'exception

    } catch (Exception e){traiter l'exception e

    }

    instruction suivante

  • 5/28/2018 Cours Csharp

    29/253

    Les bases de C# 29

    Si la fonction ne gnre pas d'exception, on passe alors instruction suivante, sinon on passe dans le corps de la clause catchpuis instruction suivante. Notons les points suivants :

    eest un objet driv du type Exception. On peut tre plus prcis en utilisant des types tels que IOException, SystemException,etc : il existe plusieurs types d'exceptions. En crivant catch (Exception e), on indique qu'on veut grer toutes les typesd'exceptions. Si le code de la clause tryest susceptible de gnrer plusieurs types d'exceptions, on peut vouloir tre plus prcisen grant l'exception avec plusieurs clausescatch:

    try{appel de la fonction susceptible de gnrer l'exception

    } catch (IOException e){traiter l'exception e

    }} catch (SystemException e){traiter l'exception e

    }instruction suivante

    On peut ajouter aux clauses try/ catch, une clausefinally:

    try{appel de la fonction susceptible de gnrer l'exception

    } catch (Exception e){traiter l'exception e

    }finally{code excutaprs try ou catch

    }instruction suivante

    Qu'il y ait exception ou pas, le code de la clause finallysera toujours excut.

    Dans la clause catch, on peut ne pas vouloir utiliser l'objet Exceptiondisponible. Au lieu d'crire catch (Exception e){ ..}, on crit

    alors catch(Exception){ ...}oucatch { ...}. La classeExceptiona une propritMessagequi est un message dtaillant l'erreur qui s'est produite. Ainsi si on veut afficher

    celui-ci, on crira :catch (E xception ex){Console.Error.Wri teL ine(" L 'erreur suivante s'est produite : " +ex.Message);...

    } / / catch La classeExceptiona une mthode ToStringqui rend une chane de caractres indiquant le type de l'exception ainsi que la

    valeur de la propritMessage. On pourra ainsi crire :catch (E xception ex){Console.Error.Wri teL ine(" L 'erreur suivante s'est produite : "+ex.ToString());...

    } / / catchOn peut crire aussi :catch (Exception ex){Console.Error.WriteL ine(" L 'erreur suivante s'est produite : "+ex);...

    } / / catchNous avons ici une opration string + Exceptionqui va tre automatiquement transforme enstring + Exception.ToString()par lecompilateur afin de faire la concatnation de deux chanes de caractres.

    L'exemple suivant montre une exception gnre par l'utilisation d'un lment de tableau inexistant :

    // tableaux

    // imports

    usingSystem;

    publicclasstab1{publicstaticvoidMain(String[] args){// dclaration & initialisation d'un tableau

  • 5/28/2018 Cours Csharp

    30/253

    Les bases de C# 30

    int[] tab=newint[] {0,1,2,3};inti;// affichage tableau avec un forfor(i=0; itab1tab[0]=0tab[1]=1tab[2]=2tab[3]=301

    23L'erreur suivante s'est produite : System.IndexOutOfRangeException: Exception oftype System.IndexOutOfRangeException was thrown.at tab1.Main(String[] args)

    Voici un autre exemple o on gre l'exception provoque par l'affectation d'une chane de caractres un nombre lorsque la chanene reprsente pas un nombre :

    // importsusingSystem;

    publicclassconsole1{publicstaticvoidMain(String[] args){// On demande le nomSystem.Console.Write("Nom : ");// lecture rponseString nom=System.Console.ReadLine();// on demande l'geintage=0;Boolean ageOK=false;while( ! ageOK){// questionConsole.Out.Write("ge : ");// lecture-vrification rponsetry{age=int.Parse(System.Console.ReadLine());ageOK=true;

    }catch{Console.Error.WriteLine("Age incorrect, recommencez...");

    }//try-catch}//while// affichage finalConsole.Out.WriteLine("Vous vous appelez " + nom + " et vous avez " + age + " ans");

    Console.ReadLine();}//Main}//classe

    Quelques rsultats d'excution :

    E:\data\serge\MSNET\c#\bases\1>console1Nom : dupontge : 23Vous vous appelez dupont et vous avez 23 ans

    E:\data\serge\MSNET\c#\bases\1>console1Nom : dupontge : xxAge incorrect, recommencez...

    ge : 12Vous vous appelez dupont et vous avez 12 ans

  • 5/28/2018 Cours Csharp

    31/253

    Les bases de C# 31

    1.11 Passage de paramtres une fonction

    Nous nous intressons ici au mode de passage des paramtres d'une fonction. Considrons la fonction :

    privatestaticvoidchangeInt(inta){a=30;Console.Out.WriteLine("Paramtre formel a="+a);

    }

    Dans la dfinition de la fonction, aest appel un paramtre formel. I l n'est l que pour les besoins de la dfinition de la fonctionchangeInt. I l aurait tout aussi bien pu s'appelerb. Considrons maintenant une utlisation de cette fonction :

    publicstaticvoidMain(){intage=20;changeInt(age);Console.Out.WriteLine("Paramtre effectif age="+age);

    }

    Ici dans l'instruction changeInt(age), ageest le paramtre effectif qui va transmettre sa valeur au paramtre formel a. Nous nousintressons la faon dont un paramtre formel rcupre la valeur d'un paramtre effectif.

    1.11.1 Passage par valeur

    L'exemple suivant nous montre que les paramtres d'une fonction sont par dfaut passs par valeur : c'est dire que la valeur duparamtre effectif est recopie dans le paramtre formel correspondant. On a deux entits distinctes. Si la fonction modifie leparamtre formel, le paramtre effectif n'est lui en rien modifi.

    // passage de paramtres par valeur une fonction

    usingSystem;

    publicclassparam2{publicstaticvoidMain(){intage=20;changeInt(age);Console.Out.WriteLine("Paramtre effectif age="+age);

    }privatestaticvoidchangeInt(inta){a=30;Console.Out.WriteLine("Paramtre formel a="+a);

    }}

    Les rsultats obtenus sont les suivants :

    Paramtre formel a=30Paramtre effectif age=20

    La valeur 20 du paramtre effectif a t recopie dans le paramtre formela. Celui-ci a t ensuite modifi. Le paramtre effectif estlui rest inchang. Ce mode de passage convient aux paramtres d'entre d'une fonction.

    1.11.2 Passage par rfrence

    Dans un passage par rfrence, le paramtre effectif et le paramtre formel sont une seule et mme entit.Si la fonction modifie leparamtre formel, le paramtre effectif est lui aussi modifi. En C#, ils doivent tre tous deux prcds du mot clref:

    Voici un exemple :

    // passage de paramtres par valeur une fonction

    usingSystem;

    publicclassparam2{publicstaticvoidMain(){intage=20;changeInt(refage);Console.Out.WriteLine("Paramtre effectif age="+age);

    }privatestaticvoidchangeInt(refinta){

    a=30;Console.Out.WriteLine("Paramtre formel a="+a);}

    }

  • 5/28/2018 Cours Csharp

    32/253

    Les bases de C# 32

    et les rsultats d'excution :

    Paramtre formel a=30Paramtre effectif age=30

    Le paramtre effectif a suivi la modification du paramtre formel. Ce mode de passage convient aux paramtres de sortie d'unefonction.

    1.11.3 Passage par rfrence avec le mot cl outConsidrons l'exemple prcdent dans lequel la variableagene serait pas initialise avant l'appel la fonction changeInt:

    // passage de paramtres par valeur une fonction

    usingSystem;

    publicclassparam2{publicstaticvoidMain(){intage;changeInt(refage);Console.Out.WriteLine("Paramtre effectif age="+age);

    }privatestaticvoidchangeInt(refinta){a=30;Console.Out.WriteLine("Paramtre formel a="+a);

    }}

    Lorsqu'on compile ce programme, on a une erreur :

    Use of unassigned local variable 'age'

    On peut contourner l'obstacle en affectant une valeur initiale age. On peut aussi remplacer le mot cl refpar le mot clout. Onexprime alors que la paramtre est uniquement un paramtre de sortie et n'a donc pas besoin de valeur initiale :

    // passage de paramtres par valeur une fonction

    usingSystem;

    publicclassparam2{

    publicstaticvoidMain(){intage=20;changeInt(outage);Console.Out.WriteLine("Paramtre effectif age="+age);

    }privatestaticvoidchangeInt(outinta){a=30;Console.Out.WriteLine("Paramtre formel a="+a);

    }}

  • 5/28/2018 Cours Csharp

    33/253

    Classes, Structures, Interfaces 33

    2. Classes, stuctures, interfaces

    2.1 L' objet par l'exemple

    2.1.1 Gnralits

    Nous abordons maintenant, par l'exemple, la programmation objet. Un objet est une entit qui contient des donnes qui dfinissentson tat (on les appelle des proprits) et des fonctions (on les appelle des mthodes). Un objet est cr selon un modle qu'onappelle une classe :

    public class C1{type1 p1; // proprit p1type2 p2; // proprit p2type3 m3(){ // mthode m3

    }type4 m4(){ // mthode m4

    }

    }

    A partir de la classe C1prcdente, on peut crer de nombreux objetsO1, O2,Tous auront les proprits p1, p2,et lesmthodesm3, m4, Mais ils auront des valeurs diffrentes pour leurs propritspiayant ainsi chacun un tat qui leur est propre.Par analogie la dclaration

    int i,j;

    cre deux objets (le terme est incorrect ici) de type (classe)int. Leur seule proprit est leur valeur.

    SiO1est un objet de typeC1,O1.p1dsigne la propritp1deO1etO1.m1la mthodem1deO1.

    Considrons un premier modle d'objet : la classepersonne.

    2.1.2 Dfinition de la classe personne

    La dfinition de la classepersonnesera la suivante :

    publicclasspersonne{// attributsprivatestringprenom;privatestringnom;privateintage;

    // mthodepublicvoidinitialise(string P, string N, intage){this.prenom=P;this.nom=N;this.age=age;

    }

    // mthodepublicvoididentifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }}

    Nous avons ici la dfinition d'une classe, donc d'un type de donnes. Lorsqu'on va crer des variables de ce type, on les appellerades objets ou des instances de classes. Une classe est donc un moule partir duquel sont construits des objets.

    Les membres ou champs d'une classe peuvent tre des donnes (attributs), des mthodes (fonctions), des proprits. Les propritssont des mthodes particulires servant connatre ou fixer la valeur d'attributs de l'objet. Ces champs peuvent tre accompagnsde l'un des trois mots cls suivants :

  • 5/28/2018 Cours Csharp

    34/253

    Classes, Structures, Interfaces 34

    priv Un champ priv (private) n'est accessible que par les seules mthodes internes de la classepublic Un champ public (public) est accessible par toute fonction dfinie ou non au sein de la classeprotg Un champ protg (protected) n'est accessible que par les seules mthodes internes de la classe ou d'un

    objet driv (voir ultrieurement le concept d'hritage).

    En gnral, les donnes d'une classe sont dclares prives alors que ses mthodes et proprits sont dclares publiques. Celasignifie que l'utilisateur d'un objet (le programmeur)

    n'aura pas accs directement aux donnes prives de l'objet pourra faire appel aux mthodes publiques de l'objet et notamment celles qui donneront accs ses donnes prives.

    La syntaxe de dclaration d'un objet est la suivante :

    public class objet{privateprivateprivateprivate donne ou mthode ou proprit privepublicpublicpublicpublic donne ou mthode ou proprit publiqueprotectedprotectedprotectedprotected donne ou mthode ou proprit protge

    }

    L'ordre de dclaration des attributsprivate, protected et publicest quelconque.

    2.1.3 La mthode initialise

    Revenons notre classe personne dclare comme :

    publicclasspersonne{// attributsprivatestringprenom;privatestringnom;privateintage;

    // mthodepublicvoidinitialise(string P, string N, intage){this.prenom=P;this.nom=N;this.age=age;

    }

    // mthodepublicvoididentifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }}

    Quel est le rle de la mthodeinitialise? Parce quenom,prenometagesont des donnes prives de la classepersonne, les instructions :

    personne p1;p1.prenom="Jean";p1.nom="Dupont";p1.age=30;

    sont illgales. Il nous faut initialiser un objet de typepersonnevia une mthode publique. C'est le rle de la mthode initialise. Oncrira :

    personne p1;p1.initialise("Jean","Dupont",30);

    L'criture p1.initialiseest lgale car initialiseest d'accs public.

    2.1.4 L'oprateur new

    La squence d'instructions

    personne p1;p1.initialise("Jean","Dupont",30);

    est incorrecte. L'instruction

    personne p1;

    dclarep1comme une rfrence un objet de typepersonne. Cet objet n'existe pas encore et doncp1n'est pas initialis. C'est commesi on crivait :

  • 5/28/2018 Cours Csharp

    35/253

    Classes, Structures, Interfaces 35

    personne p1=null;

    o on indique explicitement avec le mot clnullque la variablep1ne rfrence encore aucun objet. Lorsqu'on crit ensuite

    p1.initialise("Jean","Dupont",30);

    on fait appel la mthode initialisede l'objet rfrenc parp1. Or cet objet n'existe pas encore et le compilateur signalera l'erreur.Pour quep1rfrence un objet, il faut crire :

    personne p1=new personne();

    Cela a pour effet de crer un objet de typepersonnenon encore initialis : les attributsnomet prenomqui sont des rfrences d'objetsde typeStringauront la valeur null, et agela valeur 0. I l y a donc une initialisation par dfaut. Maintenant quep1rfrence un objet,l'instruction d'initialisation de cet objet

    p1.initialise("Jean","Dupont",30);

    est valide.

    2.1.5 Le mot cl this

    Regardons le code de la mthodeinitialise:publicpublicpublicpublicvoidvoidvoidvoidinitialise(string P, string N, intintintintage){

    thisthisthisthis.prenom=P;thisthisthisthis.nom=N;thisthisthisthis.age=age;

    }

    L'instruction this.prenom=Psignifie que l'attribut prenomde l'objet courant (this) reoit la valeur P. Le mot cl thisdsigne l'objetcourant : celui dans lequel se trouve la mthode excute. Comment le connat-on ? Regardons comment se fait l'initialisation del'objet rfrenc par p1 dans le programme appelant :

    p1.initialise("Jean","Dupont",30);

    C'est la mthode initialisede l'objet p1qui est appele. Lorsque dans cette mthode, on rfrence l'objetthis, on rfrence en fait

    l'objet p1. La mthode initialiseaurait aussi pu tre crite comme suit :publicpublicpublicpublicvoidvoidvoidvoidinitialise(string P, string N, intintintintage){

    prenom=P;nom=N;thisthisthisthis.age=age;

    }

    Lorsqu'une mthode d'un objet rfrence un attributA de cet objet, l'criture this.A est implicite. On doit l'utiliser explicitementlorsqu'il y a conflit d'identificateurs. C'est le cas de l'instruction :

    thisthisthisthis.age=age;

    o agedsigne un attribut de l'objet courant ainsi que le paramtre agereu par la mthode. I l faut alors lever l'ambigut endsignant l'attributagepar this.age.

    2.1.6 Un programme de test

    Voici un court programme de test :

    usingSystem;

    publicclasspersonne{// attributsprivatestringprenom;privatestringnom;privateintage;

    // mthodepublicvoidinitialise(stringP, stringN, intage){

    this.prenom=P;this.nom=N;this.age=age;

    }

    // mthode

  • 5/28/2018 Cours Csharp

    36/253

    Classes, Structures, Interfaces 36

    publicvoididentifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }}

    publicclasstest1{publicstaticvoidMain(){personne p1=newpersonne();p1.initialise("Jean","Dupont",30);p1.identifie();

    }}

    et les rsultats obtenus :

    E:\data\serge\MSNET\c#\objetsPoly\1>C:\WINNT\Microsoft.NET\Framework\v1.0.2914\csc.exe personne1.csMicrosoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

    E:\data\serge\MSNET\c#\objetsPoly\1>personne1Jean,Dupont,30

    2.1.7 Utiliser un fichier de classes compiles (assembly)

    On notera que dans l'exemple prcdent il y a deux classes dans notre programme de test : les classespersonneet test1. Il y a uneautre faon de procder :

    - on compile la classe personne dans un fichier particulier appel un assemblage (assembly). Ce fichier a une extension .dll- on compile la classe test1 en rfrenant l'assemblage qui contient la classe personne.

    Les deux fichiers source deviennent les suivants :

    test1.cs public class test1{public static void Main(){personne p1=new personne();p1.initialise("Jean","Dupont",30);p1.identifie();

    }

    }//classe test1

    personne.csusing System;

    public class personne{// attributsprivate string prenom;private string nom;private int age;

    // mthodepublic void initialise(string P, string N, int age){this.prenom=P;this.nom=N;this.age=age;

    }

    // mthodepublic void identifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }}// classe personne

    La classepersonneest compile par l'instruction suivante :

    E:>csc.exe /t:library personne.csMicrosoft (R) Visual C# Compiler Version 7.00.9254 [CLR version v1.0.2914]Copyright (C) Microsoft Corp 2000-2001. All rights reserved.

    E:\data\serge\MSNET\c#\objetsPoly\2>dir26/04/2002 08:24 520 personne.cs26/04/2002 08:26 169 test1.cs26/04/2002 08:26 3 584 personne.dll

    La compilation a produit un fichier personne.dll. C'est l'option de compilation/ t:libraryqui indique de produire un fichier "assembly".Maintenant compilons le fichier test1.cs:

  • 5/28/2018 Cours Csharp

    37/253

    Classes, Structures, Interfaces 37

    E:\data\serge\MSNET\c#\objetsPoly\2>csc /r:personne.dll test1.cs

    E:\data\serge\MSNET\c#\objetsPoly\2>dir26/04/2002 08:24 520 personne.cs26/04/2002 08:26 169 test1.cs26/04/2002 08:26 3 584 personne.dll26/04/2002 08:53 3 072 test1.exe

    L'option de compilation/ r:personne.dllindique au compilateur qu'il trouvera certaines classes dans le fichierpersonne.dll. Lorsque dansle fichier source

    test1.cs, il trouvera une rfrence la classe

    personneclasse non dclare dans le source

    test1.cs, il cherchera la classe

    personnedans les fichiers .dll rfrencs par l'option/ r. I l trouvera ici la classepersonnedans l'assemblage personne.dll. On aurait pumettre dans cet assemblage d'autres classes. Pour utiliser lors de la compilation plusieurs fichiers de classes compiles, on crira :

    csc /r:fic1.dll /r:fic2.dll ... fichierSource.cs

    L'excution du programmetest1.exedonne les rsultats suivants :

    E:\data\serge\MSNET\c#\objetsPoly\2>test1Jean,Dupont,30

    2.1.8 Une autre mthode initialise

    Considrons toujours la classepersonneet rajoutons-lui la mthode suivante :

    publicvoidinitialise(personne P){prenom=P.prenom;nom=P.nom;this.age=P.age;

    }

    On a maintenant deux mthodes portant le nom initialise: c'est lgal tant qu'elles admettent des paramtres diffrents. C'est le casici. Le paramtre est maintenant une rfrenceP une personne. Les attributs de la personnePsont alors affects l'objet courant(this). On remarquera que la mthode initialisea un accs direct aux attributs de l'objetPbien que ceux-ci soient de typeprivate. C'esttoujours vrai : un objetO1d'une classeCa toujours accs aux attributs des objets de la mme classeC.

    Voici un test de la nouvelle classepersonne, celle-ci ayant t compile danspersonne.dllcomme il a t expliqu prcdemment :usingSystem;

    publicclasstest1{publicstaticvoidMain(){personne p1=newpersonne();p1.initialise("Jean","Dupont",30);Console.Out.Write("p1=");p1.identifie();personne p2=newpersonne();p2.initialise(p1);Console.Out.Write("p2=");p2.identifie();

    }}

    et ses rsultats :

    p1=Jean,Dupont,30p2=Jean,Dupont,30

    2.1.9 Constructeurs de la classe personne

    Un constructeur est une mthode qui porte le nom de la classe et qui est appele lors de la cration de l'objet. On s'en sertgnralement pour l'initialiser. C'est une mthode qui peut accepter des arguments mais qui ne rend aucun rsultat. Son prototypeou sa dfinition ne sont prcds d'aucun type (mme pasvoid).

    Si une classe a un constructeur acceptant n arguments argi, la dclaration et l'initialisation d'un objet de cette classe pourra se faire

    sous la forme :

    classe objet =new classe(arg1,arg2, ... argn);ou

  • 5/28/2018 Cours Csharp

    38/253

    Classes, Structures, Interfaces 38

    classe objet;objet=new classe(arg1,arg2, ... argn);

    Lorsqu'une classe a un ou plusieurs constructeurs, l'un de ces constructeurs doit tre obligatoirement utilis pour crer un objet decette classe. Si une classeCn'a aucun constructeur, elle en a un par dfaut qui est le constructeur sans paramtres : public C(). Lesattributs de l'objet sont alors initialiss avec des valeurs par dfaut. C'est ce qui s'est pass lorsque dans les programmes prcdents,o on avait crit :

    personne p1;p1=new personne();

    Crons deux constructeurs notre classepersonne:

    usingSystem;

    publicclasspersonne{// attributsprivatestringprenom;privatestringnom;privateintage;

    // constructeurspublicpersonne(String P, String N, intage){initialise(P,N,age);

    }

    publicpersonne(personne P){initialise(P);}

    // mthodes d'initialisation de l'objetpublicvoidinitialise(stringP, stringN, intage){this.prenom=P;this.nom=N;this.age=age;

    }publicvoidinitialise(personne P){prenom=P.prenom;nom=P.nom;this.age=P.age;

    }

    // mthodepublicvoididentifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }}

    Nos deux constructeurs se contentent de faire appel aux mthodesinitialisecorrespondantes. On rappelle que lorsque dans unconstructeur, on trouve la notation initialise(P)par exemple, le compilateur traduit par this.initialise(P). Dans le constructeur, lamthode initialiseest donc appele pour travailler sur l'objet rfrenc parthis, c'est dire l'objet courant, celui qui est en cours deconstruction.

    Voici un court programme de test :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){personne p1=new personne("Jean","Dupont",30);

    Console.Out.Write("p1=");p1.identifie();personne p2=newpersonne(p1);Console.Out.Write("p2=");p2.identifie();

    }}

    et les rsultats obtenus :

    p1=Jean,Dupont,30p2=Jean,Dupont,30

    2.1.10 Les rfrences d'objets

    Nous utilisons toujours la mme classepersonne. Le programme de test devient le suivant :

    usingSystem;

  • 5/28/2018 Cours Csharp

    39/253

    Classes, Structures, Interfaces 39

    publicclasstest1{publicstaticvoidMain(){// p1personne p1=new personne("Jean","Dupont",30);Console.Out.Write("p1="); p1.identifie();// p2 rfrence le mme objet que p1personne p2=p1;Console.Out.Write("p2="); p2.identifie();// p3 rfrence un objet qui sera une copie de l'objet rfrenc par p1personne p3=newpersonne(p1);Console.Out.Write("p3="); p3.identifie();// on change l'tat de l'objet rfrenc par p1p1.initialise("Micheline","Benot",67);Console.Out.Write("p1="); p1.identifie();// comme p2=p1, l'objet rfrenc par p2 a du changer d'tatConsole.Out.Write("p2="); p2.identifie();// comme p3 ne rfrence pas le mme objet que p1, l'objet rfrenc par p3 n'a pas du changerConsole.Out.Write("p3="); p3.identifie();

    }}

    Les rsultats obtenus sont les suivants :

    p1=Jean,Dupont,30p2=Jean,Dupont,30p3=Jean,Dupont,30p1=Micheline,Benot,67p2=Micheline,Benot,67

    p3=Jean,Dupont,30

    Lorsqu'on dclare la variablep1par

    personne p1=new personne("Jean","Dupont",30);

    p1rfrence l'objetpersonne(" Jean" ,"Dupont" ,30)mais n'est pas l'objet lui-mme. En C, on dirait que c'est un pointeur, c.a.d. l'adressede l'objet cr. Si on crit ensuite :

    p1=null

    Ce n'est pas l'objet personne(" Jean","Dupont" ,30) qui est modifi, c'est la rfrence p1 qui change de valeur. L'objetpersonne(" Jean" ,"Dupont" ,30)sera "perdu" s'il n'est rfrenc par aucune autre variable.

    Lorsqu'on crit :

    personne p2=p1;

    on initialise le pointeur p2: il "pointe" sur le mme objet (il dsigne le mme objet) que le pointeurp1. Ainsi si on modifie l'objet"point" (ou rfrenc) parp1, on modifie celui rfrenc parp2.

    Lorsqu'on crit :

    personne p3=new personne(p1);

    il y a cration d'un nouvel objet, copie de l'objet rfrenc par p1. Ce nouvel objet sera rfrenc parp3. Si on modifie l'objet"point" (ou rfrenc) parp1, on ne modifie en rien celui rfrenc parp3. C'est ce que montrent les rsultats obtenus.

    2.1.11 Les objets temporaires

    Dans une expression, on peut faire appel explicitement au constructeur d'un objet : celui-ci est construit, mais nous n'y avons pasaccs (pour le modifier par exemple). Cet objet temporaire est construit pour les besoins d'valuation de l'expression puisabandonn. L'espace mmoire qu'il occupait sera automatiquement rcupr ultrieurement par un programme appel "ramasse-miettes" dont le rle est de rcuprer l'espace mmoire occup par des objets qui ne sont plus rfrencs par des donnes duprogramme.

    Considrons le nouveau programme de test suivant :

    usingSystem;

    public class test1{public static void Main(){new personne(new personne("Jean","Dupont",30)).identifie();

    }}

  • 5/28/2018 Cours Csharp

    40/253

    Classes, Structures, Interfaces 40

    et modifions les constructeurs de la classepersonneafin qu'ils affichent un message :

    // constructeurspublicpersonne(String P, String N, intage){Console.Out.WriteLine("Constructeur personne(String, String, int)");initialise(P,N,age);

    }publicpersonne(personne P){Console.Out.WriteLine("Constructeur personne(personne)");initialise(P);

    }

    Nous obtenons les rsultats suivants :

    Constructeur personne(String, String, int)Constructeur personne(personne)Jean,Dupont,30

    montrant la construction successive des deux objets temporaires.

    2.1.12 Mthodes de lecture et d'criture des attributs privs

    Nous rajoutons la classepersonneles mthodes ncessaires pour lire ou modifier l'tat des attributs des objets :

    usingSystem;

    publicclasspersonne{

    // attributsprivateString prenom;privateString nom;privateintage;

    // constructeurspublicpersonne(String P, String N, intage){this.prenom=P;this.nom=N;this.age=age;

    }

    publicpersonne(personne P){

    this.prenom=P.prenom;this.nom=P.nom;this.age=P.age;

    }

    // identifiepublicvoididentifie(){Console.Out.WriteLine(prenom+","+nom+","+age);

    }

    // accesseurspublicString getPrenom(){returnprenom;

    }publicString getNom(){returnnom;

    }publicintgetAge(){returnage;

    }

    //modifieurspublicvoidsetPrenom(String P){this.prenom=P;

    }publicvoidsetNom(String N){this.nom=N;

    }publicvoidsetAge(intage){this.age=age;

    }}//classe

    Nous testons la nouvelle classe avec le programme suivant :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){personne P=new personne("Jean","Michelin",34);

  • 5/28/2018 Cours Csharp

    41/253

    Classes, Structures, Interfaces 41

    Console.Out.WriteLine("P=("+P.getPrenom()+","+P.getNom()+","+P.getAge()+")");P.setAge(56);Console.Out.WriteLine("P=("+P.getPrenom()+","+P.getNom()+","+P.getAge()+")");

    }

    }

    et nous obtenons les rsultats suivants :

    P=(Jean,Michelin,34)P=(Jean,Michelin,56)

    2.1.13 Les proprits

    Il existe une autre faon d'avoir accs aux attributs d'une classe c'est de crer des proprits. Celles-ci nous permettent de manipulerdes attributs privs comme s'ils taient publics.

    Considrons la classepersonnesuivante o les accesseurs et modifieurs prcdents ont t remplacs par despropritsen lecture etcriture :

    usingSystem;

    publicclasspersonne{

    // attributsprivateString _prenom;privateString _nom;privateint_age;

    // constructeurspublicpersonne(String P, String N, intage){this._prenom=P;this._nom=N;this._age=age;

    }

    publicpersonne(personne P){this._prenom=P._prenom;this._nom=P._nom;this._age=P._age;

    }

    // identifiepublicvoididentifie(){Console.Out.WriteLine(_prenom+","+_nom+","+_age);

    }

    // propritspublicstringprenom{get{ return_prenom; }set{ _prenom=value; }

    }//prenom

    publicstringnom{get{ return_nom; }set{ _nom=value; }

    }//nom

    publicintage{get{ return_age; }set{// age valide ?if(value>=0){_age=value;

    } elsethrownewException("ge ("+value+") invalide");

    }//if}//age

    }//classe

    Une proprit permet de lire (get) ou de fixer (set) la valeur d'un attribut. Dans notre exemple, nous avons prfix les noms desattributs du signe _ afin que les proprits portent le nom des attributs primitifs. En effet, une proprit ne peut porter le mmenom que l'attribut qu'elle gre car alors il y a un conflit de noms dans la classe. Nous avons donc appel nos attributs_prenom,_nom,

    _ageet modifi les constructeurs et mthodes en consquence. Nous avons ensuite cr trois propritsnom, prenomet age. Uneproprit est dclare comme suit :

    public type proprit{ get {...} set {...}}

  • 5/28/2018 Cours Csharp

    42/253

    Classes, Structures, Interfaces 42

    o typedoit tre le type de l'attribut gr par la proprit. Elle peut avoir deux mthodes appelesgetet set. La mthodegetesthabituellement charge de rendre la valeur de l'attribut qu'elle gre (elle pourrait rendre autre chose, rien ne l'empche). La mthodesetreoit un paramtre appel valuequ'elle affecte normalement l'attribut qu'elle gre. Elle peut en profiter pour faire desvrifications sur la validit de la valeur reue et ventuellement lancer un exception si la valeur se rvle invalide. C'est ce qui est faitici pour l'ge.

    Comment ces mthodesgetetsetsont-elles appeles ? Considrons le programme de test suivant :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){personne P=new personne("Jean","Michelin",34);Console.Out.WriteLine("P=("+P.prenom+","+P.nom+","+P.age+")");P.age=56;Console.Out.WriteLine("P=("+P.prenom+","+P.nom+","+P.age+")");try{P.age=-4;

    } catch(Exception ex){Console.Error.WriteLine(ex.Message);

    }//try-catch}//Main

    }//classe

    Dans l'instructionConsole.Out.WriteLine("P=("+P.prenom+","+P.nom+","+P.age+")");

    on cherche avoir les valeurs des propritsprenom, nomet agede la personne P. C'est la mthodegetde ces proprits qui est alorsappele et qui rend la valeur de l'attribut qu'elles grent.

    Dans l'instructionP.age=56;

    on veut fixer la valeur de la propritage. C'est alors la mthode set de cette proprit qui est alors appele. Elle recevra 56 dans sonparamtrevalue.

    Une proprit Pd'une classe Cqui ne dfinirait que la mthode getest dite en lecture seule. Si c est un objet de classe C,l'oprationc.P= valeursera alors refuse par le compilateur.

    L'excution du programme de test prcdent donne les rsultats suivants :

    P=(Jean,Michelin,34)P=(Jean,Michelin,56)ge (-4) invalide

    Les proprits nous permettent donc de manipuler des attributs privs comme s'ils taient publics.

    2.1.14 Les mthodes et attributs de classe

    Supposons qu'on veuille compter le nombre d'objets personnes cres dans une application. On peut soi-mme grer un compteurmais on risque d'oublier les objets temporaires qui sont crs ici ou l. Il semblerait plus sr d'inclure dans les constructeurs de laclasse personne, une instruction incrmentant un compteur. Le problme est de passer une rfrence de ce compteur afin que leconstructeur puisse l'incrmenter : il faut leur passer un nouveau paramtre. On peut aussi inclure le compteur dans la dfinition dela classe. Comme c'est un attribut de la classe elle-mme et non d'un objet particulier de cette classe, on le dclare diffremment

    avec le mot clstatic:private static long _nbPersonnes; // nombre de personnes cres

    Pour le rfrencer, on crit personne._nbPersonnespour montrer que c'est un attribut de la classepersonneelle-mme. Ici, nous avonscr un attribut priv auquel on n'aura pas accs directement en-dehors de la classe. On cre donc une proprit publique pourdonner accs l'attribut de classenbPersonnes. Pour rendre la valeur de nbPersonnesla mthodegetde cette proprit n'a pas besoind'un objet personneparticulier : en effet _nbPersonnesn'est pas l'attribut d'un objet particulier, il est l'attribut de toute une classe. Aussia-t-on besoin d'une proprit dclare elle-aussistatic:

    // proprit de classepublicstaticlongnbPersonnes{get{ return_nbPersonnes;}

    }//nbPersonnes

    qui de l'extrieur sera appele avec la syntaxepersonne.nbPersonnes. Voici un exemple.

    La classepersonnedevient la suivante :

  • 5/28/2018 Cours Csharp

    43/253

    Classes, Structures, Interfaces 43

    usingSystem;

    publicclasspersonne{

    // attributs de classeprivatestaticlong_nbPersonnes=0;

    // attributs d'instanceprivateString _prenom;privateString _nom;privateint_age;

    // constructeurspublicpersonne(String P, String N, intage){// une personne de plus_nbPersonnes++;this._prenom=P;this._nom=N;this._age=age;

    }

    publicpersonne(personne P){// une personne de plus_nbPersonnes++;this._prenom=P._prenom;this._nom=P._nom;this._age=P._age;

    }

    // identifie

    publicvoididentifie(){Console.Out.WriteLine(_prenom+","+_nom+","+_age);

    }

    // proprit de classepublicstaticlongnbPersonnes{get{ return_nbPersonnes;}

    }//nbPersonnes

    // proprits d'instancepublicstringprenom{get{ return_prenom; }set{ _prenom=value; }

    }//prenom

    publicstringnom{get{ return_nom; }set{ _nom=value; }

    }//nompublicintage{get{ return_age; }set{// age valide ?if(value>=0){_age=value;

    } elsethrownewException("ge ("+value+") invalide");

    }//if}//age

    }//classe

    Avec le programme suivant :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){personne p1=new personne("Jean","Dupont",30);personne p2=newpersonne(p1);newpersonne(p1);Console.Out.WriteLine("Nombre de personnes cres : "+personne.nbPersonnes);

    }// main}//test1

    on obtient les rsultats suivants :

    Nombre de personnes cres : 3

    2.1.15 Passage d'un objet une fonction

  • 5/28/2018 Cours Csharp

    44/253

    Classes, Structures, Interfaces 44

    Nous avons dj dit que par dfaut C# passait les paramtres effectifs d'une fonction par valeur : les valeurs des paramtreseffectifs sont recopies dans les paramtres formels. Dans le cas d'un objet, il ne faut pas se laisser tromper par l'abus de langage quiest fait systmatiquement en parlant d'objet au lieu de rfrence d'objet. Un objet n'est manipul que via une rfrence (un pointeur)sur lui. Ce qui est donc transmis une fonction, n'est pas l'objet lui-mme mais une rfrence sur cet objet. C'est donc la valeur dela rfrence et non la valeur de l'objet lui-mme qui est duplique dans le paramtre formel : il n'y a pas construction d'un nouvelobjet.

    Si une rfrence d'objet R1 est transmise une fonction, elle sera recopie dans le paramtre formel correspondant R2. Aussi lesrfrences R2 et R1 dsignent-elles le mme objet. Si la fonction modifie l'objet point par R2, elle modifie videmment celui

    rfrenc par R1 puisque c'est le mme.

    C'est ce que montre l'exemple suivant :

    usingSystem;publicclasstest1{publicstaticvoidMain(){// une personne p1personne p1=new personne("Jean","Dupont",30);// affichage p1Console.Out.Write("Paramtre effectif avant modification : ");p1.identifie();// modification p1modifie(p1);// affichage p1Console.Out.Write("Paramtre effectif aprs modification : ");p1.identifie();

    }// main

    privatestaticvoidmodifie(personne P){// affichage personne PConsole.Out.Write("Paramtre formel avant modification : ");

    P.identifie();// modification PP.prenom="Sylvie";P.nom="Vartan";P.age=52;// affichage PConsole.Out.Write("Paramtre formel aprs modification : ");P.identifie();

    }// modifie

    }// class

    La mthodemodifieest dclarestaticparce que c'est une mthode de classe : on n'a pas la prfixer par un objet pour l'appeler.

    Les rsultats obtenus sont les suivants :

    Construction personne(string, string, int)Paramtre effectif avant modification : Jean,Dupont,30Paramtre formel avant modification : Jean,Dupont,30Paramtre formel aprs modification : Sylvie,Vartan,52Paramtre effectif aprs modification : Sylvie,Vartan,52

    On voit qu'il n'y a construction que d'un objet : celui de la personne p1de la fonction Mainet que l'objet a bien t modifi par lafonctionmodifie.

    2.1.16 Un tableau de personnes

    Un objet est une donne comme une autre et ce titre plusieurs objets peuvent tre rassembls dans un tableau :

    importpersonne;

    usingSystem;

    publicclasstest1{

    R1 objet

    R2

    Recopie

  • 5/28/2018 Cours Csharp

    45/253

    Classes, Structures, Interfaces 45

    publicstaticvoidMain(){// un tableau de personnespersonne[] amis=newpersonne[3];amis[0]=new personne("Jean","Dupont",30);amis[1]=new personne("Sylvie","Vartan",52);amis[2]=new personne("Neil","Armstrong",66);// affichageConsole.Out.WriteLine("----------------"); inti;for(i=0;i

  • 5/28/2018 Cours Csharp

    46/253

    Classes, Structures, Interfaces 46

    _nbPersonnes++;// constructionthis._prenom=P._prenom;this._nom=P._nom;this._age=P._age;// suiviConsole.Out.WriteLine("Construction personne(string, string, int)");

    }

    // proprit de classepublicstaticlongnbPersonnes{get{ return_nbPersonnes;}

    }//nbPersonnes

    // proprits d'instancepublicstringprenom{get{ return_prenom; }set{ _prenom=value; }

    }//prenom

    publicstringnom{get{ return_nom; }set{ _nom=value; }

    }//nom

    publicintage{get{ return_age; }set{// age valide ?if(value>=0){_age=value;

    } elsethrownewException("ge ("+value+") invalide");}//if

    }//age

    publicstringidentite{get{ return "personne("+_prenom+","+_nom+","+age+")";}

    }

    }//classe

    La mthode identifiea t remplace par la proprit identiten lecture seule et qui identifie la personne. Nous crons une classeenseignant hritant de la classepersonne:

    usingSystem;

    publicclassenseignant : personne {

    // attributsprivateint_section;

    // constructeurpublicenseignant(stringP, stringN, intage,intsection) : base(P,N,age) {this._section=section;// suiviConsole.Out.WriteLine("Construction enseignant(string,string,int,int)");

    }//constructeur

    // proprit sectionpublicintsection{get{ return_section; }set{ _section=value; }

    }// section}//classe

    La classeenseignantrajoute aux mthodes et attributs de la classepersonne:

    " un attribut sectionqui est le n de section auquel appartient l'enseignant dans le corps des enseignants (une section pardiscipline en gros)

    " un nouveau constructeur permettant d'initialiser tous les attributs d'un enseignant

    La dclarationpublic classenseignant : personne {

    indique que la classeenseignantdrive de la classepersonne.

    2.2.2 Construction d'un objet enseignant

    Le constructeur de la classeenseignantest le suivant :

    // constructeurpublicenseignant(String P, String N, intage,intsection) : base(P,N,age) {

  • 5/28/2018 Cours Csharp

    47/253

    Classes, Structures, Interfaces 47

    this._section=section;}//constructeur

    La dclaration

    publicenseignant(String P, String N, intage,intsection) : base(P,N,age) {

    dclare que le constructeur reoit quatre paramtresP, N, age, sectionet en passe trois (P,N ,age) sa classe de base, ici la classepersonne. On sait que cette classe a un constructeur personne(string, string, int)qui va permettre de construire une personne avec lesparamtres passss (P,N ,age). Une fois la construction de la classe de base termine, la construction de l'objet enseignantse poursuit

    par l'excution du corps du constructeur :this.s_ection=section;

    En rsum, le constructeur d'une classe drive :" passe sa classe de base les paramtres dont elle a besoin pour se construire" utilise les autres paramtres pour initialiser les attributs qui lui sont propres

    On aurait pu prfrer crire :

    // constructeurpublicenseignant(String P, String N, intage,intsection){this._prenom=P;this._nom=Nthis._age=age

    this._section=section;}

    C'est impossible. La classepersonnea dclar privs (private) ses trois champs _prenom, _nomet _age. Seuls des objets de la mme classeont un accs direct ces champs. Tous les autres objets, y compris des objets fils comme ici, doivent passer par des mthodespubliques pour y avoir accs. Cela aurait t diffrent si la classe personneavait dclar protgs (protected) les trois champs : elleautorisait alors des classes drives avoir un accs direct aux trois champs. Dans notre exemple, utiliser le constructeur de la classeparent tait donc la bonne solution et c'est la mthode habituelle : lors de la construction d'un objet fils, on appelle d'abord leconstructeur de l'objet parent puis on complte les initialisations propres cette fois l'objet fils (sectiondans notre exemple).

    Compilons les classespersonneetenseignantdans des assemblages :

    E:\data\serge\MSNET\c#\objetsPoly\12>csc /t:library personne.csE:\data\serge\MSNET\c#\objetsPoly\12>csc /r:personne.dll /t:library enseignant.cs

    E:\data\serge\MSNET\c#\objetsPoly\12>dir26/04/2002 16:15 1 341 personne.cs26/04/2002 16:30 4 096 personne.dll26/04/2002 16:32 345 enseignant.cs26/04/2002 16:32 3 072 enseignant.dll

    On remarquera que pour compiler la classe filleenseignant, il a fallu rfrencer le fichierpersonne.dllqui contient la classepersonne.

    Tentons un premier programme de test :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){Console.Out.WriteLine(new enseignant("Jean","Dupont",30,27).identite);

    }

    }

    Ce programme ce contente de crer un objetenseignant(new) et de l'identifier. La classeenseignantn'a pas de mthode identitmais saclasse parent en a une qui de plus est publique : elle devient par hritage une mthode publique de la classeenseignant. Les rsultatsobtenus sont les suivants :

    Construction personne(string, string, int)Construction enseignant(string,string,int,int)

    personne(Jean,Dupont,30)

    On voit que :" un objetpersonnea t construit avant l'objetenseignant" l'identit obtenue est celle de l'objetpersonne

    2.2.3 Surcharge d'une mthode ou d'une proprit

  • 5/28/2018 Cours Csharp

    48/253

    Classes, Structures, Interfaces 48

    Dans l'exemple prcdent, nous avons eu l'identit de la partie personnede l'enseignant mais il manque certaines informationspropres la classeenseignant(la section). On est donc amen crire une proprit permettant d'identifier l'enseignant :

    usingSystem;

    publicclassenseignant : personne {// attributsprivateint_section;

    // constructeurpublicenseignant(stringP, stringN, intage,intsection) : base(P,N,age) {

    this._section=section;// suiviConsole.Out.WriteLine("Construction enseignant(string,string,int,int)");

    }//constructeur

    // proprit sectionpublicintsection{get{ return_section; }set{ _section=value; }

    }// section

    // surcharge proprit identitpublicnewstringidentite{get{ return"enseignant("+base.identite+","+_section+")"; }

    }//proprit identit

    }//classe

    La mthode identitede la classe enseignants'appuie sur la mthode identitede sa classe mre (base.identite) pour afficher sa partie"personne" puis complte avec le champ _sectionqui est propre la classe enseignant. Notons la dclaration de la proprit identite:publicnewstringidentite{

    Soit un objetenseignantE. Cet objet contient en son sein un objetpersonne:

    La proprit identit est dfinie la fois dans la classeenseignantet sa classe mrepersonne. Dans la classe fille enseignant, la propritidentitedoit tre prcde du mot clnewpour indiquer qu'on redfinit une nouvelle propritidentitepour la classeenseignant.

    publicnewstringidentite{

    La classeenseignantdispose maintenant de deux proprits identite:" celle hrite de la classe parentpersonne" la sienne propre

    Si E est un ojet enseignant, E.identitedsigne la mthode identitede la classeenseignant. On dit que la proprit identitede la classe mreest "surcharge" par la proprit identitede la classe fille. De faon gnrale, siOest un objet etMune mthode, pour excuter la

    mthodeO.M, le systme cherche une mthodeMdans l'ordre suivant :" dans la classe de l'objet O" dans sa classe mre s'il en a une" dans la classe mre de sa classe mre si elle existe" etc

    L'hritage permet donc de surcharger dans la classe fille des mthodes/proprits de mme nom dans la classe mre. C'est ce quipermet d'adapter la classe fille ses propres besoins. Associe au polymorphisme que nous allons voir un peu plus loin, la surchargede mthodes/proprits est le principal intrt de l'hritage.

    Considrons le mme exemple que prcdemment :

    usingSystem;

    publicclasstest1{publicstaticvoidMain(){Console.Out.WriteLine(new enseignant("Jean","Dupont",30,27).identite);

    }}

    ensei