Top Banner
Langage C# - Les Bases 1
128

Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Mar 27, 2018

Download

Documents

hoangthu
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Langage C# - Les Bases

1

Page 2: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Table des matières

Langage C# - Les Bases ___________________________________________________________________ 1 Chapitre 1 : Visual Studio .NET ______________________________________________________________ 7

1. Introduction _________________________________________________________________________ 7 2. Fonctionalités de Visual Studio .Net_______________________________________________________ 7

2.1 L'éditeur de texte __________________________________________________________________ 7 2.2 L'éditeur graphique_________________________________________________________________ 7 2.3 Les fenêtres de support _____________________________________________________________ 7 2.4 Le débogueur intégré. ______________________________________________________________ 8 2.5 Le système d'aide intégré (MSDN). ____________________________________________________ 8 2.6 L'accès à des logiciels externes._______________________________________________________ 8 2.7 Conclusion________________________________________________________________________ 8

3. Première approche de Visual Studio .net___________________________________________________ 9 3.1 Premier lancement de Visual Studio .Net_______________________________________________ 10 3.2. Création d'un nouveau projet _______________________________________________________ 11 3.3. Les différents types de projet C# ____________________________________________________ 12 3.4. Différencier les "Solutions" et les "Projets"_____________________________________________ 14

Notes pour les utilisateurs des versions précédentes de Visual Studio _________________________ 14 4 Les différentes fenêtres de l'IDE_________________________________________________________ 15

4.1. Fenêtre "Explorateur de Solutions". __________________________________________________ 15 4.2. La fenêtre "Propriétés" ____________________________________________________________ 17 4.3. La fenêtre "Affichage de Classes" ____________________________________________________ 18 4.4. La fenêtre "Dynamic Help" _________________________________________________________ 20 4.5. La Boite à outils ou ToolBox ________________________________________________________ 21 4.6. L'explorateur de Serveurs (Server Explorer). ___________________________________________ 22 4.7. Autres fenêtres de l'IDE ___________________________________________________________ 23

4.7.1 La fenêtre "Task List" __________________________________________________________ 23 4.7.2 La fenêtre "Command Window" __________________________________________________ 23 4.7.3 La fenêtre "Output" ____________________________________________________________ 24 4.7.4 La fenêtre "Autos" _____________________________________________________________ 24 4.7.5 La fenêtre "Locals"_____________________________________________________________ 24 4.7.6 La fenêtre "Call Stack" ou "pile des appels" _________________________________________ 25 4.7.7 La fenêtre "BreakPoints" ________________________________________________________ 25

5. Fenêtre "Explorateur d'objets" ou "Object Browser" _______________________________________ 26 Chapitre 2 : Syntaxe du Langage C# ________________________________________________________ 27

1. Considérations générales sur la syntaxe __________________________________________________ 27 1.1 Espaces blancs _________________________________________________________________ 27 1.2 Instructions____________________________________________________________________ 27 1.3 Structuration par Blocs___________________________________________________________ 27 1.4 Indentation du code _____________________________________________________________ 28 1.5 Commentaires____________________________________________________________________ 29

Commentaires simple ligne : //________________________________________________________ 29 Commentaires multi-lignes : /* … */ ___________________________________________________ 29 Commentaires de documentation XML : /// ______________________________________________ 29

1.5 Sensiblité à la Casse_____________________________________________________________ 31 2. Notre premier programme : HelloWorld.cs ________________________________________________ 32 3. Les Variables dans C# ________________________________________________________________ 33

3.1 Concept de variable _______________________________________________________________ 33 3.2 Représentation en mémoire ________________________________________________________ 34

2

Page 3: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Base 10 __________________________________________________________________________ 34 Notation Binaire____________________________________________________________________ 34 Types numériques signés et non-signés_________________________________________________ 35 Chaînes de caractères (Strings) _______________________________________________________ 35

3.3 Déclaration de variables ____________________________________________________________ 37 3.4 Initialisation de variables ___________________________________________________________ 38 3.5 Nommage des variables ____________________________________________________________ 39 3.6 Portée des variables _______________________________________________________________ 40

Exemple__________________________________________________________________________ 40 Différences entre champs et variables locales ____________________________________________ 41

3.7 Constantes ______________________________________________________________________ 42 4 Les types de données dans C#__________________________________________________________ 43

4.1 Types "Valeur" et Types "Référence"__________________________________________________ 43 Exemple d'affectation à un type valeur _________________________________________________ 43 Exemple d'affectation à un type Référence ______________________________________________ 43 Conclusion ________________________________________________________________________ 44

4.2 Types du Common Type System _____________________________________________________ 46 4.3 Types Valeur prédéfinis ____________________________________________________________ 46

Types d'entiers ____________________________________________________________________ 46 Types de nombres en virgule flottante__________________________________________________ 47 Type Decimal______________________________________________________________________ 47 Type bool (Booléen) ________________________________________________________________ 48 Type Char (caractère)_______________________________________________________________ 48

4.4 Types Référence prédéfinis _________________________________________________________ 49 Type object _______________________________________________________________________ 49 Type string _______________________________________________________________________ 50

5. opérateurs et expressions _____________________________________________________________ 52 5.1 Différents types d'opérateurs ________________________________________________________ 52 5.2 Opérateurs et raccourcis ___________________________________________________________ 53 5.3 L'operateur ternaire _______________________________________________________________ 54 5.4 Opérateurs checked et unchecked____________________________________________________ 54 5.5 Opérateur sizeof __________________________________________________________________ 55 5.6 Opérateur typeof _________________________________________________________________ 55 5.7 Préséance des opérateurs __________________________________________________________ 55 5.8 Sécurité et Types _________________________________________________________________ 56

6. Conversions de types de données _______________________________________________________ 56 6.1 Conversions implicites _____________________________________________________________ 56 6.2 Conversions explicites______________________________________________________________ 58 6.3 Boxing et un-Boxing _______________________________________________________________ 60

7. Contrôle du Flux d'exécution ___________________________________________________________ 61 7.1 Les Instruction Conditionnelles ______________________________________________________ 61

L'instruction if _____________________________________________________________________ 61 L'instruction switch _________________________________________________________________ 63

7.2 Les Boucles______________________________________________________________________ 65 La boucle for ______________________________________________________________________ 65 La boucle while ____________________________________________________________________ 67 La boucle do…while_________________________________________________________________ 67 La boucle foreach __________________________________________________________________ 68

7.3 Instruction de saut ________________________________________________________________ 69 L'instruction goto___________________________________________________________________ 69 L'instruction break__________________________________________________________________ 69 L'instruction continue _______________________________________________________________ 69 L'instruction return _________________________________________________________________ 69

3

Page 4: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3. Chapitre 3 : Structure des programmes ____________________________________________________ 70 3.1 Les Tableaux en C# _________________________________________________________________ 70

3.1.1 Définition ______________________________________________________________________ 70 3.1.2 Les tableaux à une dimension______________________________________________________ 70

Initialisation_______________________________________________________________________ 70 Accès aux éléments du tableau _______________________________________________________ 71

3.1.3 Les tableaux à plusieurs dimensions_________________________________________________ 71 3.1.4 Les tableaux orthogonaux (jagged arrays)____________________________________________ 72

Déclaration _______________________________________________________________________ 72 Initialisation_______________________________________________________________________ 72 Parcours des tableaux de tableaux_____________________________________________________ 73

3.1.5 La classe Array et ses méthodes. ___________________________________________________ 74 Propriétés de System.Array Class__________________________________________________ 74 Méthodes de System.Array Class. _________________________________________________ 74

3.2. Les Enumérations __________________________________________________________________ 75 3.2.1 Définition et usage ______________________________________________________________ 75 3.2.2 Typage sous-jacent des énumérations _______________________________________________ 75 3.2.3 Méthodes de la classe Enum_______________________________________________________ 76

3.3 Les espaces de noms (namespaces) ____________________________________________________ 76 3.3.1 importance des espaces de nom____________________________________________________ 76 3.3.2 Conventions pour namespaces et répertoires__________________________________________ 77 3.3.3 Instruction using ________________________________________________________________ 78 3.3.4 Liste des principaux namespaces ___________________________________________________ 78

3.4 Classes et Structures ________________________________________________________________ 79 3.4.2 Définir des classes et des structures_________________________________________________ 79

Structures ________________________________________________________________________ 79 Classes___________________________________________________________________________ 80

3.4.3 Différence entre une classe et un objet.______________________________________________ 80 3.5 Méthodes dans C# __________________________________________________________________ 81

3.5.1 Déclaration de méthodes _________________________________________________________ 81 3.5.2 valeurs de retour ________________________________________________________________ 81 3.5.3 Invocation de méthodes __________________________________________________________ 81 3.5.4 La méthode Main et ses différentes syntaxes__________________________________________ 81 3.5.5 Passage d'arguments à Main_______________________________________________________ 82 3.5.6 Passage d'arguments par valeur et par référence ______________________________________ 83

Mot-clé ref ________________________________________________________________________ 83 Mot-clé Out _______________________________________________________________________ 83

3.5.7 Passage de tableaux aux méthodes _________________________________________________ 83 Mot-clé Params ____________________________________________________________________ 84

3.5.8 Surcharger des méthodes. ________________________________________________________ 84 3.5.9 Membres statiques et Membres d'instance____________________________________________ 85

3.6 Propriétés _________________________________________________________________________ 86 3.6.1 Concept d'encapsulation __________________________________________________________ 86 3.6.2 Syntaxe des propriétés ___________________________________________________________ 87 3.6.3 Considérations générales _________________________________________________________ 88

Lecture / écriture___________________________________________________________________ 88 Accès différents____________________________________________________________________ 88

3.6.4 Indexeurs______________________________________________________________________ 88 3.7 Delegates et Evènements ____________________________________________________________ 89

3.7.1 Définition d'un Delegate __________________________________________________________ 89 3.7.2 Exemple d'utilisation d'un delegate simple ____________________________________________ 89 3.7.2 Delegates Multicast ______________________________________________________________ 90 3.7.1 Evènements____________________________________________________________________ 91

4

Page 5: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Etape 1: Déclarer le delegate. ________________________________________________________ 92 Etape 2: Définir la classe Generateur ___________________________________________________ 92 Etape 3: Définir la classe Client _______________________________________________________ 93 Etape 4: Souscrire à l'évènement et le traiter ____________________________________________ 93

4. Chapitre 4 : Déboguage et gestion d’erreurs ________________________________________________ 94 1. Introduction ________________________________________________________________________ 94 2. Déboguage dans Visual Studio .net______________________________________________________ 94

2.1 Déboguage en mode « normal » _____________________________________________________ 95 2.2 Afficher des informations de déboguage utiles __________________________________________ 95 2.3 Déboguage en mode ‘point d’arrêt’ ou pas à pas ________________________________________ 96

2.3.1 Entrer en mode Point d’arrêt_____________________________________________________ 96 2.3.2 Définir des point d’arrêt dans le code ______________________________________________ 97 2.3.3 Autres moyens d’activer le mode arrêt _____________________________________________ 99

3. Contrôler le contenu des variables______________________________________________________ 100 3.1 La fenêtre « Variables locales » _____________________________________________________ 100 3.2 La fenêtre « Recherche »__________________________________________________________ 100 3.3 Différents mode de pas à pas ______________________________________________________ 101 3.4 La fenêtre « Command » __________________________________________________________ 101 3.5 La fenêtre « Pile des appels » ______________________________________________________ 102

4. Gestion des Erreurs _________________________________________________________________ 103 4.1 Les exceptions __________________________________________________________________ 103 4.2 La structure « try..catch..finally » ___________________________________________________ 103 4.3 Lister et configurer des exceptions __________________________________________________ 105 4.5 La Fenêtre Exceptions ____________________________________________________________ 105

Chapitre 5 - Concepts Orientés Objet _______________________________________________________ 106 5.1 Constructeurs ___________________________________________________________________ 106

5.1.1 Par défaut __________________________________________________________________ 106 5.1.2 Paramétrés__________________________________________________________________ 106 5.1.3 Statiques ___________________________________________________________________ 106 5.1.4 Appeler d'autres constructeurs depuis un constructeur._______________________________ 107 5.1.5 Appeler des constructeurs de la classe de base _____________________________________ 107

5.2 Destructeurs ____________________________________________________________________ 109 5.2.1 Syntaxe ____________________________________________________________________ 109 5.2.2 Notion de Garbage Collector et Finalisation non-déterministe __________________________ 109 5.2.3 Interface IDisposable et Méthode Dispose. ________________________________________ 110

5.6 Héritage _______________________________________________________________________ 111 5.6.1 Héritage de classes ___________________________________________________________ 111 5.6.2 le mot-clé this _______________________________________________________________ 111 5.6.3 le mot-clé base ______________________________________________________________ 111 5.6.4 Redéfinition de méthodes ______________________________________________________ 113 5.6.4 Masquage de méthodes________________________________________________________ 114

5.7 Interfaces ______________________________________________________________________ 114 5.7.2 Implémentation d'interfaces ____________________________________________________ 115 5.7.2 Polymorphisme par les interfaces ________________________________________________ 115 5.7.3 Héritage d'interfaces __________________________________________________________ 117

5.7 Classes ________________________________________________________________________ 118 5.7.1 Classes abstraites ____________________________________________________________ 118 5.7.2 Classes sealed _______________________________________________________________ 119 5.7.3 Niveau d'accessibilité des classes et des membres. __________________________________ 119

Annexe 1 – Conventions de codage en C#. __________________________________________________ 121 1. Introduction _____________________________________________________________________ 121 2. Conventions de nommage __________________________________________________________ 121 3. Casse des noms d'éléments (Pascal Casing et Camel Casing) ______________________________ 122

5

Page 6: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4. Style des Noms d'éléments. _________________________________________________________ 123 5. Nommage des Namespaces (espaces de noms). ________________________________________ 123

Annexe 2 : Caractères d'échappement ______________________________________________________ 124 Annexe 3 – Noms et Mots-Clés ____________________________________________________________ 125

1. Liste des mots-clés Visual Basic .NET _________________________________________________ 125 2. Liste des mots-clés C# _____________________________________________________________ 127

6

Page 7: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Chapitre 1 : Visual Studio .NET

1. Introduction Visual Studio .Net est l’environnement de développement intégré de Microsoft. Il a été conçu pour rendre aussi faciles que possible l’écriture, le déboguage et la compilation de vos programmes.

2. Fonctionalités de Visual Studio .Net En pratique, cela signifie que Visual Studio .Net est une application extrêmement sophistiquée, présentant une interface multi-documents, et dans laquelle vous pourrez effectuer toutes les opérations nécessaires au développement de votre code. Concrètement, l’application VS.NET comporte :

2.1 L'éditeur de texte Dans l'éditeur de texte, vous pouvez écrire votre code, quel que soit le langage que vous utilisez. Tous les langages écrits pour supporter la plateforme .Net sont pris en compte. Cela inclut C#, Visual Basic .Net, C++ .Net, ainsi que tous les autres langages d’éditeurs tiers (tel Eiffel.Net, Python.Net, etc..). Cet éditeur profite des derniers développements en matière d'interface utilisateur et supporte la nouvelle version de la technologie IntelliSense® qui apporte aux développeurs plus de souplesse et de rapidité dans l'écriture de leur code.

2.2 L'éditeur graphique L'éditeur graphique (ou désigner) permet d'élaborer de manière visuelle une interface utilisateur, que celle-ci soit une interface Windows ou une interface Web. Lorsque vous utilisez ce "designer", Visual Studio .Net traduit automatiquement l'interface graphique les diverses actions réalisées par les développeurs pour créer l'interface graphique en code C# (ou n'importe quel autre langage .Net). Les utilisateurs de RAD (comme Visual Basic 6 par exemple) sont déjà habitués à pouvoir créer graphiquement leurs interfaces, mais, auparavant, le code généré était caché aux développeurs, ce qui induisait certaines limitations. Ce n'est plus le cas dans le designer graphique de Visual Studio .Net : toutes les opérations réalisées en mode "graphique" par les développeurs sont désormais traduites en code.

2.3 Les fenêtres de support Cellecs-ci permettent de visualiser et de modifier certains aspects de votre projet. Il existe ainsi des fenêtres pour accéder aux propriétés des objets, des fenêtres permettant l'accès à l'aide, des fenêtres permettant la visualisation des valeurs des variables, etc. Nous étudierons certaines de ces fenêtre plus loin dans ce chapitre.

7

Page 8: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

2.4 Le débogueur intégré. Il arrive souvent que l'on fasse des erreurs lors d'un processus de développement. Visual Studio .Net comporte donc un débogueur qui vous informe de la nature de ces erreurs, et permet de les identifier plus facilement. Il peut même analyser en temps réel la syntaxe du code que vous êtes en train de taper afin de vous aider à localiser ces erreurs.

2.5 Le système d'aide intégré (MSDN). Le système d'aide de Microsoft, nommé "MSDN" (pour Microsoft Developper Network) est étroitement intégré au fonctionnement de Visual Studio .Net. Ce système d'aide fait partie du package Visual Studio et peut être consulté en tant que tel, mais peut également être consulté au sein même de l'environnement de développement Visual Studio. Visua Studio peut bien sûr appeler la documentation MSDN de façon contextuelle. Par exemple, si vous hésitez sur la signification d'un mot-clé, vous pouvez le sélectionner dans le code, taper sur la touche F1 et Visual Studio .Net affichera la page appropriée dans la documentation MSDN. De nombreuses options sont disponibles permettant à chaque développeur d'appliquer ses préférences personnelles en ce qui concerne le degré d'intégration de MSDN dans Visual Studio .Net.

2.6 L'accès à des logiciels externes. Visual Studio .Net est un outil très ouvert et, par conséquent, permet aux développeurs de personnaliser leur environnement de développement. Parmi les options disponibles, on trouve la possibilité d'exécuter depuis Visual Studio .net des programmes divers paramétrables par les utilisateurs, tout cela sans quitter l'environnement de développement. On peut même naviguer sur le Web au sein de Visual Studio !

2.7 Conclusion Comme vous le constatez, Visual Studio .Net est plus qu'un simple éditeur de texte. Il est l'outil le plus pratique pour créer des applications .Net. Cependant, cet outil n'est pas obligatoirement nécessaire pour créer des applications .net : un simple éditeur de texte (comme NotePad) pourrait suffire.. Evidemment, NotePad n'offre pas la même souplesse que Visual Studio .net mais, Microsoft ayant inclus les différents compilateurs dans le Framework SDK (téléchargeable gratuitement sur http://msdn.microsoft.com), il est tout à fait possible de ne pas utiliser Visual Studio pour coder des logiciels .net.

Par ailleurs, d'autres éditeurs très professionnels sont téléchargeables sur Internet comme par exemple SharpDevelop et WebMatrix (en source libre) ou encore DreamWeaver MX (édité par MacroMedia).

SharpDevelop : http://www.icsharpcode.net/OpenSource/SD/Download/WebMatrix : http://www.asp.net/webmatrix/download.aspx?tabindex=0&tabid=1DreamWeaverMX: http://www.macromedia.com/software/dreamweaver/download/

8

Page 9: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3. Première approche de Visual Studio .net Dans cette section nous présenterons les différentes fonctionnalités de L'IDE Visual Studio .net et les différents types de projets que nous pouvons créer en langage C#. Ce chapitre n'a pas pour but de présenter de manière exhaustive toutes les fonctionnalités de l'IDE car il faudrait pour cela un livre entier ! En effet, cet environnement de développment est si complet qu'il est sans doute plus facile de découvrir ses fonctionnalités avancées au fur et à mesure que nous en aurons l'utilité dans le code. Le très grand nombre de fonctionnalités dans Visual Studio .net tient également au fait que cet IDE permet, outre le développement d'un grand nombre de projets différents, d'utiliser tous les langages implémentant le Framework.net et tout cela dans le même logiciel. De plus, Visual Studio .net peut également servir d'interface pour interagir avec des bases de données ou des services Windows, en présentant une interface graphique adaptée à chacune de ces tâches. Commençons par découvrir ensemble les fonctionnalités "de tous les jours" de Visual Studio .net.

9

Page 10: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.1 Premier lancement de Visual Studio .Net Voici la page d'accueuil de VS.NET telle que vous la verrez lors du premier lancement après l'installation :

Cette page est appelée la "page d'accueuil" de Visual Studio .Net. C'est une page HTML qui présente plusieurs onglets :

• Projects : présente la liste des projets récemment utilisés ou permet la création d'un nouveau projet.

• Online Resources: cette page vous présente différents liens utiles vers la communauté de

développeurs et d'éditeurs travaillant avec la plateforme .net. Par exemple, on peut directement faire des recherches sur MSDN version Web, télécharger des exemples de code, rechercher des services Web effectuant une tâche particulière, etc.. C'est un peu une porte sur le monde de .net. De plus, cette page est configurable et il est possible d'y ajouter ses propres éléments ou services Web.

• My Profile : Cet onglet vous permet de définir certaines options pour l'environnement de

développement Visual Studio, telles que la configuration du clavier (par exemple les anciens développeurs VB peuvent avoir exactement les mêmes raccourcis clavier que dans les version

10

Page 11: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

précédentes de Visual Studio), l'agencement des fenêtres, le filtre pour l'aide (par exemple pour n'afficher que l'aide concernant un langage particulier et pas les autres), et enfin si vous souhaitez utiliser l'aide MSDN dans une fenêtre intégrée à Visual Studio ou si vous préférez utiliser celle-ci en tant que logiciel tournant indépendamment de Visual Studio.

3.2. Création d'un nouveau projet Vous pouvez créer un nouveau projet soit en cliquant sur le lien approprié sur la page d'accueuil de Visual Studio, soit en allant dans le menu "Fichier\Nouveau\Projet". Dans les deux cas, la boite de dialogue "Nouveau Projet" s'affiche et vous permet de définir les options et le type du nouveau projet à créer. Voici comment se présente cette boite de dialogue :

Comme on peut le voir, il existe de nombreux types de projets différents disponibles pour le langage C#. Nous allons expliquer la nature de certains d'entre eux prochainement. On constate que cette boite de dialogue nous permet également de définir le répertoire utilisé pour stocker le projet, ainsi que le nom du projet à créer. La case à cocher "Créer un répertoire pour la solution" introduit le concept de "solution", qui est une notion différente de celle du projet. Nous étudierons les différences entre un projet et une solution dans ce chapitre.

11

Page 12: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.3. Les différents types de projet C# Note : Le but de ce suppor n'est pas de décrire exhaustivement tous les types de projets pour tous les types de langages. Pour information, en ce qui concerne C++, tous les anciens types de projets sont disponibles (applications MFC, projets ATL, etc..). En ce qui concerne Visual Basic .NET il existe des innovations (avec de nouveaux types de projets comme par exemple "Application Console").

t

En ce qui concerne C#, nous nous bornerons ici à décrire les types de projets principaux que nous pouvons créer sous C#. Il existe cependant d'autres types de projets C# plus spécialisés sous l'option "Other Projects"ou "Autres projets".

C# permet donc la création de nombreux types de projet. Le type d'un projet permet de définir le type d'application qui va résulter de la compilation et du déploiement de ce projet.

Type de Projet sélectionné Obtention du Code C# et des options de compilation pour générer

Application Windows Un projet contenant un formulaire de base vide répondant aux évènements. Ce type de projet sert à créer des applications avec des interfaces client sous Windows (des EXE)

Bibliothèque de Classes Un projet compilable sous la forme de DLL contenant une ou plusieurs classes réutilisable(s) par un autre programme .net

Bibliothèque de contrôles Windows Un projet contenant une classe .net possédant une interface utiilisateur et réutilisable par un autre programme .net (comme un contrôle ActiveX dans les versions précédentes de VS.

Application Web ASP.NET Un projet contenant une WebForm (page ASP.NET) et permettant de créer une application avec une interface Web. Les pages ASP.NET générant automatiquement le code HTML visualisé dans l'explorateur Internet.

Service Web ASP.NET Un projet contenant une classe agissant comme un service Web. Un service Web est une application qui tourne sur un serveur Web et dont un autre programme peut se servir.

Bibliothèque de contrôles Web Un projet contenant un contrôle réutilisable et pouvant être appelé depuis une page ASP.NET et qui générera le code HTML nécessaire à son affichage dans un explorateur Internet

Type de Projet sélectionné Obtention du Code C# et des options de

12

Page 13: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

compilation pour générer

Application Console Un projet contenant une classe .net et les options de compilation nécessaire à la création d'un projet qui s'exécutera dans une fenêtre de commande DOS.

Service Windows Un projet destiné à générer une application de type "service". Un service est une application en général sans interface graphique et tournant en arrière-plan de Windows (NT, XP, 2000 ou plus).

Projet Vide Un projet vide. Lors de la création d'un tel projet, vous devrez écrire tout le code en partant de rien. Vous continuerez cependant à bénéficier de toutes les facilités et outils de Visual Studio .Net lors de l'écriture du code.

Projet Web Vide Un projet vide mais avec des paramètres de compilation définis pour annoncer au compilateur de générer du code pour des pages ASP.Net

Nouveau Projet dans un dossier existant Des fichiers d'un nouveau projet pour un projet vide. Utilisez cette option si vous disposez de fichiers de code source C# (saisis par exemple dans un éditeur de texte) et que vous souhaitez les intégrer dans un projet Visual Studio .Net

13

Page 14: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.4. Différencier les "Solutions" et les "Projets" Nous avons déjà évoqué précédemment dans ce chapitre les termes "solution" et "projet". Ces deux notions sont différentes et il est important de bien comprendre la différence entre les deux..

• Un projet est l'ensemble de tous les fichiers de code source et des fichiers de ressources compilables dans un seul assemblage (ou programme). Par exemple, un projet peut être une bibliothèque de classe ou une application avec interface utilisateur Windows, ou encore une application s'exécutant dans une fenêtre DOS (application "Console").

• Une Solution est constituée de l'ensemble de tous les projets faisant partie d'un ensemble logiciel

particulier destiné à créer une application. Pour mieux comprendre cette différence, rappelons-nous que, lors de la livraison d'une application, cette dernière est vraisemblablement composée du plus d'un assemblage.

Par exemple, cette application pourrait contenir une interface utilisateur, quelques contrôles personnalisés et d'autres composants livrés comme des bibliothèques de composants d'application. On pourrait dans certains cas y ajouter encore d'autre éléments, comme par exemple une interface utilisateur spécifique réservée aux administrateurs.

Chacune de ces parties pourrait être contenue dans un assemblage séparé, pour des raisons évidentes de réutilisation et de modularité du code. Toutes ces parties, prises séparément, sont chacune considérées comme un projet individuel par Visua Studio. Toutefois, il est plausible que vous dévelopiez tous ces projet en parralèle, les uns interagissant avec les autres.

Il serait donc très utile de conserver la possibilité de les éditer comme ensemble unitaire au sein de votre environnement de développement. Visual Studio .Net le permet en considérant que tous les projets font partie d'une seule solution et traite cette solution comme une seule unité qu'il lit et stocke en mémoire et dans laquelle il permet de travailler.

C'est pourquoi le comportement par défaut de Visual Studio .net est de créer une solution pour tout nouveau projet que vous créez. Si vous souhaitez ne travailler que sur un seul projet, le fait que celui-ci soit contenu dans une solution sera transparent. Par contre, si par la suite vous voulez intégrer votre projet avec d'autres, il vous suffira d'ajouter les autres projets à la solution pour permettre, par exemple, la compilation de tous les projets contenus dans la solution d'un seul coup.

Notes pour les utilisateurs des versions précédentes de Visual Studio Pour les développeurs C++, une solution Visual Studio .NET correspond à un ancien "espace de travail" de projet Visual C++ 6 (stocké dans un fichier .dsw) et un projet Visual Studio .NET correspond à un ancien projet C++ (fichiers .dsp). Pour les développeurs en VB (version 4,5 ou 6), une solution correspond à l'ancienne notion de groupe de projet (fichiers .vbg) et un projet .NET rappelle l'ancien projet VB (fichier .vbp)

14

Page 15: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4 Les différentes fenêtres de l'IDE Dans cette section, nous allons détailler les différentes fenêtres les plus utilisées dans l'IDE (Integrated Development Environment). Le but n'est pas un passage en revue exhaustif de toutes les fenêtres disponibles mais de donner un aperçu des fenêtre que l'on utilise couramment.

4.1. Fenêtre "Explorateur de Solutions". Voici une image de la fenêtre "explorateur de solution" :

Cette fenêtre permet de visualiser les divers fichiers composant les projets ou solutions actuellement ouverts dans Visual Studio .Net. On voit la relation hiérarchique symbolisée par les différents niveaux dans l'arbre contenant tous les éléments avec, en haut la solution contenant le ou les projets qui la constitue. On voit en dessous le projet ("CCsshhaarrppNN11 –– AArrrraayyss") et en dessous, les divers élements du projet, comme suit :

• la boite de dialogue "Références" qui, une fois déroulée montrent l'ensemble des assemblages référencés par ce projet

• Les fichiers constituant le projet (avec deux fichiers de code C# avec une extension .cs, une icône qui

deviendra celle de l'application, et un fichier texte associé au projet).

15

Page 16: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Lorsque l'on souhaite faire afficher dans la fenêtre concepteur (graphique ou de code) un élément en particulier, il suffit de double-cliquer sur son icône ou son nom dans l'explorateur de projets et le contenu dudit fichier est affiché. NB : Pour renommer un élément, il est toujours conseillé d'utiliser cette fenêtre plutot que de passer par l'explorateur Windows. En effet, si l'on renomme un élément en dehors de Visual Studio, la modification de nom n'est pas répercutée dans Visual Studio, ce qui conduit l'IDE à ne plus retrouver le fichier renommé. Dans cet exemple, la solution affiichée ne contient qu'un seul projet mais, dans un processus de développement réel, il n'est pas rare d'avoir plusieurs projets ouverts dans une même solution.

16

Page 17: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.2. La fenêtre "Propriétés" Voici une autre fenêtre que les développeurs ayant utilisé les versions précédentes de Visual Basic reconnaîtront certainement. Nous avons déjà évoqué le fait que les classes pouvaient contenir des propriétés. Nous verrons en détail comment implémenter des propriétés pour une classe donnée dans les chapitres suivants. Voici comment se présente la fenêtre propriétés :

Cette fenêtre est faite pour nous permettre d'interagir avec les propriétés d'un objet donné. Une fois un objet sélectionné (si celui-ci posséde des propriétés bien sûr), les noms et les valeurs de chacune des propriétés de cet objet s'affichent dans la fenêtre propriétés. On voit au sommet de cette fenêtre, une liste déroulante contenant la liste de tous les objets dont les propriétés peuvent être affichées par cette fenêtre. Dans cet exemple, on constate que l'objet dont les propriétés sont actuellement affichées s'appelle Form1 et est de type SSyysstteemm..WWiinnddoowwss..FFoorrmmss..FFoorrmm.

17

Page 18: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

On peut bien sûr interagir avec les valeurs des propriétés via cette fenêtre. Toutes les modifications de propriétés que nous effectuons via cette fenêtre donneront lieu à des modifications dans le code source de l'élement affiché. Il est donc préférable d'utiliser la fenêtre propriétés quand cela est possible car cela nous évite d'écrire du code et c'est beaucoup plus facile ! La zone de l'image qui affiche le texte "Misc" est la zone de description qui, une fois une propriété sélectionnée, affiche une description succinte de l'usage de la propriété (pour avoir des informations détaillées, l'aide MSDN est bien sûr plus complète).

4.3. La fenêtre "Affichage de Classes" Contrairement à la fenêtre propriétés, la fenêtre "affichage de classes" (ou ClassView) trouve son origine dans les environnements de développement C++ et Java. Voici comment se présente cette fenêtre :

Comme on peut le constater, la fenêtre "affichage de classes" n'est pas à proprement parler une fenêtre indépendante, mais se présente comme un onglet supplémentaire de l'explorateur de solutions. Elle affiche une vue en arborescence que vous pouvez dérouler pour visualiser exhaustivement les éléments composant votre solution. Dans cet exemple, on voit que la solution ne contient qu'une seule classe nommée CCllaassssTTeessttAArrrraayyss, située dans le namespace DDeemmooss..CCsshhaarrppNN11..AArrrraayyss. On voit en dessous du nœud de la classe, la liste des membres de la classes, en l'occurrence, la liste des méthodes que cette classe propose, comme par exemple la méthode MMaaiinn((SSttrriinngg[[]])), la méthode pprriinnttVVaalluueess((iinntt[[]])), etc.. Cette vue hiérarchique de tous les éléments de code composant une solution est extrèmement pratique, tant pour la vision globale qu'elle offre, mais également pour atteindre rapidement un élément dans le code. Il

18

Page 19: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

suffit en effet de double-cliquer sur un élément pour que l'éditeur de code se positionne immédiatement sur celui-ci. On utilisera donc très souvent cette fenêtre pour se déplacer dans le code, ainsi que pour garder une vision globale claire de tous les élémements (classes, méthodes, propriétés, etc..) composant une solution. Icônes du ClassView Vous constaterez que chacun des éléments affichés dans cette fenêtre possède une ou deux icône particulières. Il y a des icônes pour tous les types d'élements que vous pouvez rencontrer dans C#, et également, une icône indiquant l'accessibilité (pprriivvaattee,, ppuubblliicc,, pprrootteecctteedd,, eettcc....) du membre que vous êtes en train de visualiser. Une référence complète des icônes et de leur signification est disponible sur le Web.

19

Page 20: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.4. La fenêtre "Dynamic Help" Voici comment se présente la fenêtre "Dynamic Help"

Cette fenêtre permet d'accéder à l'aide MSDN (Microsoft Developer Network) fournie avec Visual Studio. Elle s'appelle "Dynamic Help" car elle son contenu évolue dynamiquement en fonction du contexte dans lequel on se trouve. Par exemple, le contenu de cette fenêtre évolue selon le mot-clé qui se trouve sous le curseur lorsque l'on est dans la fenêtre de code, ou encore selon l'objet actuellement sélectionné dans l'IDE, par exemple un bouton ou un autre contrôle situé sur une feuille. NB: cette fenêtre est pratique mais le fait de la garder affichée ralentit le fonctionnement de la technologie d'auto-complétion du code avec IntelliSense.

20

Page 21: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.5. La Boite à outils ou ToolBox La Toolbox est une fenêtre qui vous permet d'ajouter différents types d'éléments dans vos projets. Cette fenêtre n'est pas toujours utile dans tous les types de projets (par exemple, on s'en sert rarement dans un projet de type "Console Application". Elle est principalement utillisée pour aider les développeurs à composer l'interface graphique des applications qui peuvent en posséder une (Application WinForms ou WebForms par exemple), en leur présentant une liste des divers éléments ajoutables dans l'interface sous forme d'icônes.. C'est par exemple via cette fenêtre que l'on pourra ajouter des boutons et autres éléments aux designer graphique pour les Windows Forms.. Voici une représentation de la fenêtre ToolBox telle qu'elle se présente dans une application Windows Forms :

On remarque que les différents types de contrôles ou d'éléments sont regroupés thématiquement dans les différents onglets au sommet de la fenêtre ("My User Controls", "Data", "Components", "Windows Forms", etc..). Cette fenêtre a également d'autres fonctionnalités (comme le "Clipboard Ring") qui seront détaillées au fur et à mesure de ce cours.

21

Page 22: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.6. L'explorateur de Serveurs (Server Explorer). La fenêtre "Explorateur de Serveurs" permet de contrôler et d'accéder à certain services tournant sur la machine directement depuis l'environnement de développement Visual Studio. Il est par exemple possible d'administrer/consulter les Logs de la machine, les services tournant sur la machine, les compteurs de performances, les MessageQueue, ainsi que d'accéder à une ou plusieurs instances SQL Server déclarées sur la machine. Le fait de pouvoir interagir directement depuis l'IDE avec le serveur de bases de données est une pratique courante et extrêmement pratique. Voici une vue de la fenêtre "Explorateur de Serveurs" :

Dans ce graphique, nous pouvons voir les différents types de services disponibles (la liste n'est pas exhaustive et peut varier en fonction des services installés sur la machine) sur une machine nommée "nemesis". On voit que l'on peut explorer la structure d'une base de données (ici, la base de données exemple de Microsoft nommée "Northwind") et consulter ou modifier des données dans les tables, créer ou modifier des procédures stockées, etc..

22

Page 23: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.7. Autres fenêtres de l'IDE L'IDE Visual Studio .net possède un grand nombre de fenêtres dédiées à différentes tâches et il n'est pas possible de toutes les énumérer ici. Nous en étudierons certaines fréquemment lors de nos développement et d'autres seront moins fréquemment utilisées, tout cela dépend du type de développement que vous effectuerez. Parmi les fenêtres très couramment utilisées on peut citer :

4.7.1 La fenêtre "Task List" Cette fenêtre affiche le résultat de la compilation, recense la liste des erreurs et avertissements, et qui vous permet également d'ajouter des tâches de développement que vous devez vous rappeler de faire (un peu comme le gestionnaire de tâches d'Outlook). Voici par exemple un apercu de la fenêtre "Task List" nous présentant la liste des tâches à effectuer (en général, ce sont des erreurs ou des avertissements à corriger):

Ici, on voit clairement la nature de chaque tâche et dans quel fichier et à quelle numéro de ligne effectuer celle-ci.

4.7.2 La fenêtre "Command Window" Celle-ci possède deux modes pour deux utilisations distinctes. En mode Command, elle permet d'appeler des commandes standards de l'IDE de manière rapide (comme par exemple ajouter une classe ou fermer un projet), et en mode "Immed" (pour "Immédiat"), elle permet d'afficher la valeur de certaines variables ou expressions lors d'une exécution en pas-à-pas

23

Page 24: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.7.3 La fenêtre "Output" Cette fenêtre affiche des indications sur les évènements qui se sont produits durant l'exécution de ou des assembly qui sont chargés. Il existe d'autres fenêtres (dont nous utiliserons la plupart), dont celles dédiées au déboguage des applications et que l'on n'utilise qu'en mode pas-à-pas :

4.7.4 La fenêtre "Autos" Cette fenêtre affiche la valeur des variables contenues dans la ligne en cours d'exécution et dans la ligne qui suit. A noter qu'en Visual Basic .net, cette fenêtre affiche les valeurs pour la ligne en cours et pour les trois lignes au dessus et en dessous de la ligne en cours). On peut également via cette fenêtre modifier directement la valeur des variables affichées lors du pas-à-pas.

4.7.5 La fenêtre "Locals" Cette fenêtre permet d'afficher les valeurs de toutes les variables et éléments qui sont dans la portée en cours. On peut également modifier les valeurs de ces éléments directement via cette fenêtre durant une exécution en pas-à-pas.

24

Page 25: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.7.6 La fenêtre "Call Stack" ou "pile des appels" Cette fenêtre affiche la pile des appels de procédure et nous permet de naviguer dans le code dans à travers les différents niveaux d'appels de procédures.

4.7.7 La fenêtre "BreakPoints" Cette fneêtre affiche la liste des points d'arrêts définis dans le code avec leurs numéros de ligne, les classes et les fonctions dans lesquels ils sont définis, ainsi que les différentes conditions qui régissent leur activation, comme par exemple la condition de déclenchement et le nombre de passages obligatoires avant le déclenchement de chacun d'entre eux.

25

Page 26: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5. Fenêtre "Explorateur d'objets" ou "Object Browser" La fenêtre "Explorateur d'objets" vous permet d'examiner et de découvrir les éléments (espaces de noms, classes, structures, interfaces, énumérations, etc..) et leurs membres (méthodes, propriétés, évènements, etc..) de tous les composants existant dans ou étant référencés par l'assemblage en cours. C'est une fenêtre pratique pour avoir une vue d'ensemble des élements d'un assemblage ou espace de nommage particulier. La possibilite de trier les éléments par type, par nom ou encore par accès (ppuubblliicc,, pprriivvaattee, etc..) permet de naviguer facilement et de trouver rapidement l'information que l'on souhaite. Une fonction de recherche est également fournie qui est très pratique pour accéder rapidement à un membre donné. Voici une vue possible de l'explorateur d'objets :

Note : Il existe cependant un outil d'un éditeur tiers qui remplit toutes les fonctions de l'explorateur de projets avec une interface plus conviviale et qui présente des fonctionnalités plus complètes. Ce logiciel se nomme .net Reflector et est utilisé largement dans la communauté .net. Il est téléchargeable ici : http://www.aisto.com/roeder/dotnet En plus d'offrir de meilleures fonctionnalités (et d'être plus convivial) que l'explorateur d'objet natif de Visual Studio, .net Reflector (appelé ainsi à cause de la technologie de réflexion qui permet à du code d'inspecter les méta-attributs d'un élément), propose un desassembleur en code IL, ainsi qu'un décompilateur en Visual Basic ou en C# ! Cet outil gratuit est l'un des outils indispensables de tout développeur C# et une visite régulière sur le site de son auteur Lutz Roeder vous permettra de profiter des lumières de l'un des pionniers du développement .net.

26

Page 27: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Chapitre 2 : Syntaxe du Langage C#

1. Considérations générales sur la syntaxe La structure et le fonctionnement du code C# sont en grande partie similaires à ceux de C++ et de Java. Au premier abord, la syntaxe de C# peut paraître confuse et moins intuitive que celles de certains langages utilisant plus de mots anglais intelligibles (comme par exemple Visual Basic 6 ou VB.NET). Cependant, après une immersion dans le langage C#, vous constaterez que sa syntaxe stricte et très concise permet l'écriture d'un code extrêmement clair et facilement maintenable.

1.1 Espaces blancs A la différence des compilateurs des autres langages, le compilateur C# ne tient pas compte des espaces supplémentaires figurant dans le code, que ceux-ci soient des caractères Espace, Tabulation ou Retour chariot (caractères communément appelés espaces blancs). Ceci signifie que vous avez une totale liberté pour formater votre code comme vous le souhaitez, bien que certaines règles communément admises augmentent la lisibilité du code. Certaines conventions de codage sont présentées en annexe de ce support et vous présentent les options de formatage du code les plus courantes.

1.2 Instructions Le code C# est composé d'instructions. Chacune de ces instructions doit se terminer par un caractère "point-virgule", indiquant la fin de l'instruction. Une même ligne peut donc théoriquement comporter plusieurs instructions, cependant, il est d'usage de commencer une nouvelle ligne après chaque point-virgule de fin d'instruction Par contre, il est tout à fait courant que des instructions très longues et qui dépasseraient la largeur d'une page écran soit réparties sur plusieurs lignes. Par convention, on essaye de ne pas écrire de lignes de code dont la largeur est supérieure à celle d'un écran imaginaire de 80 colonnes, ceci parceque pratiquement tous les écrans peuvent afficher cette résolution.

1.3 Structuration par Blocs Le langage C# est un langage structuré par blocs, ce qui signifie que toutes les instructions sont encadrées dans des blocs délimités par une paire d'accolades. Ces blocs peuvent contenir une ou plusieurs instructions, ou encore être vides. Notez qu'une accolade n'est en elle-même pas une instruction et ne doit par conséquent pas être suivie d'un point-virgule. Un bloc de code C# peut dont se présenter ainsi : { <ligne de code 1, expression 1>; <ligne de code 2, expression 2> <ligne de code 3, expression 3>; }

27

Page 28: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Dans cet exemple les sections <<lliiggnnee ddee ccooddee XX,, eexxpprreessssiioonn YY>> ne sont pas du code exécutable C# mais du texte générique représentant n'importe quelle instruction. Ici, les deuxième et troisième lignes font partie de la même instruction, car la deuxième ligne ne se termine pas par un point-virgule.

1.4 Indentation du code Dans l'exemple précédent, nous avons utilisé l'indentation pour rendre le code C# plus lisible et rendre plus facile l'identification du début et de la fin des blocs. Il s'agit d'un pratique courant en programmation et cela fait partie des bonnes conventions de formattage du code. D'ailleurs, Visual Studio .net indente par défaut le code mais vous devrez le faire vous-même si vous n'utilisez qu'un éditeur de texte standard pour l'écriture du code. En régle générale, chaque bloc de code possède son propre niveau d'indentation. Les blocs de code peuvent être imbriqués les uns dans les autres et, dans ce cas, on utilise l'indentation de manière à identifier clairement de à quel bloc de code les instructions appartiennent : { <ligne de code 1>; { <ligne de code 2>; <ligne de code 3>; }

<ligne de code 4>; }

28

Page 29: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

1.5 Commentaires Les commentaires sont d'autres éléments courant dans le code C#, comme dans presque tous les langages de programmation. Il est d'usage d'insérer des commentaires décrivant l'action de blocs de code, de façon à faciliter la relecture du code. Les commentaires n'augmentent pas la taille des exécutables produits et ne sont pas pris en compte par le compilateur (sauf éventuellement pour les commentaires servant à générer la documentation XML). Il existe trois syntaxes de commentaires en C# :

Commentaires simple ligne : // Les commentaires simple ligne peuvent être placés sur n'importe quelle ligne après deux caractères "slash" ("//"). Le double-slash indique le début du commentaire et la fin de la ligne indique la fin du commentaire. // Ceci est un commentaire

Commentaires multi-lignes : /* … */ Dans cette notation, les commentaires commencent par "/*" et se terminent par "*/". Cette notation est généralement utilisée pour écrire plusieurs lignes de commentaire sans avoir à inscrire un double-slash au début de chaque ligne, ou encore pour commenter plusieurs lignes de code d'un seul coup. Le commentaire ci-dessous est valide : /* Ceci est la première ligne du commentaire Ceci est la deuxième ligne du commentaire */ ... Code ...

Le commentaire suivant génère une erreur /* les commentaires sont souvent terminés avec la syntaxe "*/" */

En effet, les caractères figurant après "/*" sont considérés comme étant hors du commentaire, ce qui entraine une erreur de compilation.

Commentaires de documentation XML : /// Il existe en C# un troisième type de commentaires qui servent à générer des fichiers d'aide. Ces commentaires ont une syntaxe spéciale basée sur XML et commencent par trois slash. Les commentaires XML possèdent différentes balises selon le type d'élement qu'ils documentent. Lors de la compilation, les commentaires XML sont extrait du code et insérés dans un fichier XML. On peut ensuite se servir de ce fichier pour générer de la documentation dans divers formats, il suffit pour cela de transformer le code XML en un format plus lisible, par exemple en HTML Visual Studio .net possèdent un outil d'auto-génération de pages web de documentation permettant la génération d'un mini-site en HTML exposant la documentation de la solution en cours sous une forme conviviale.

29

Page 30: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Voici un exemple de commentaire de documentation XML /// <summary> /// Fonction permettant l'addition de deux entiers /// </summary> /// <param name="nombre1">un entier</param> /// <param name="nombre2">un autre entier</param> /// <returns>le résultat de l'addition des deux nombres.</returns> static long addition (int nombre1, int nombre2) { return (nombre1 + nombre2); }

Dès que l'on tape un triple slash ("///"), Visual Studio analyse le type de membre au dessus duquel le curseur se trouve et génère les balises XML nécessaires à sa description dans l'aide. Il ne nous reste plus qu'à documenter le membre en question et l'aide sera automatiquement générée sur demande par Visual Studio ou un autre outil de génération de documentation XML tel l'utilitaire Ndoc (téléchargeable sur : http://ndoc.sourceforge.net/download.html) Une référence complète des balises de documentation XML se trouve dans la documentation MSDN avec le titre : "Recommended Tags for Documentation Comments" et à l'adresse : ms-help: //MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/csref/html/vclrftagsfordocumentationcom ments.htm

30

Page 31: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

1.5 Sensiblité à la Casse Il est extrêment important de noter que le langage C# est sensible à la casse, c'est-à-dire qu'il différencie les majuscules des minuscules. Cela peut causer des erreurs difficiles à trouver pour les débutants. Par exemple, si l'on considère le code suivant : ... code ... int aa; ... AA = 0; // attention ! ici AA est en majuscules

Ce code provoquera une erreur du compilateur car la variable "aa" n'est pas la même que la variable "AA" qui n'a pas été déclarée. Le compilateur indique donc que la variable "AA" n'existe pas. Ce peut paraître une contrainte mais c'est en fait très pratique pour peu que l'on se fixe des règles de codage strictes. Un certain nombre de ces règles peuvent être consultées dans l'annexe de ce support nommée "Conventions de codage". NOTE : Un excellent document sur les conventions de codage et les bonnes pratiques de programmation avec C# et .net est disponible sur le site de Juwal Lowy sur le site www.idesign net. à l'adresse suivante : http://www.componentware.net/idesign/download/IDesign CSharp Coding Standard.zip

31

Page 32: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

2. Notre premier programme : HelloWorld.cs Commençons à rentrer dans la pratique en examinant l'exemple de code suivant stocké dans le fichier "helloworld.cs" using System; namespace CSharp.Introduction { class Class1 { /// <summary> /// Point d'entrée de l'application /// </summary> [STAThread] static void Main(string[] args) { string message; message = "Hello World !"; Console.WriteLine("Hello World !"); } } }

Tout d'abord voici ce que fait cette application : elle affiche le texte "Hello World" dans la fenêtre de commande DOS. On peut constater que tous les éléments syntaxiques (points-virgule, accolades, commentaires, code indenté) abordés dans les points précédents figurent bien dans ce code. En fait, la section de code suivante est la plus importante pour notre exemple : [STAThread] static void Main(string[] args) { string message; message = "Hello World !"; Console.WriteLine(message); }

Il s'agit du code exécuté lors du lancement de l'application console. Plus exactement, le code exécuté est tout ce qui se trouve entre les accolades. Nous ne nous préoccuperons pas des autres lignes de code dans cet exemple (comme par exemple la manière dont l'application atteint l'instruction CCoonnssoollee..WWrriitteeLLiinnee((mmeessssaaggee));; car l'objectif de ce chapitre est d'étudier la syntaxe C# de base. Les premiers éléments que nous allons détailler sont les variables.

32

Page 33: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3. Les Variables dans C#

3.1 Concept de variable La mémoire vive (ou RAM) d’un ordinateur est donc constituée d’un grand nombre de cases (bbiittss), chacune d’entre elles pouvant prendre soit la valeur 0 soit la valeur 1. Chacune de ces cases possède une « adresse », ce qui permet d’identifier la case de manière unique. Or ce ne serait pas très pratique d’avoir à gérer (et à mémoriser) les adresses de toutes les données que nous désirons stocker dans la mémoire. On dispose donc de ce que l’on appelle des variables. Une variable n’est donc rien de plus qu’un zone de la mémoire, à laquelle on va référer non par son adresse mais par un nom, qui sera le nom de la variable. Lorsque l’on souhaitera interagir avec cette zone particulière de la mémoire (soit dit, lire son contenu ou écrire dans son contenu), on référera à la zone en question par le nom de la variable. Definition : Une variable est une zone dans la mémoire auquelle on a affecté un nom. Une fois une variable déclarée, on peut interagir avec la zone mémoire vers laquelle "pointe" la variable pour y stocker ou y lire des données. Les variables possèdent :

• Un nom • Un Type de données • Une portée • Une valeur

Chaque variable possède un type bien particulier qui indique au compilateur le volume nécessaire que celui-ci doit réserver dans la mémoire pour la variable. Le volume de mémoire occupé par une variable dépendra donc du type de données que l’on aura affecté à la variable. La portée d’une variable définit en gros son étendue et l'état de sa visibilité par rapport à d'autres éléments. Par exemple, si une variable vvaarrAA est définie dans une procédure PPrrooccAA(()) est-ce que la procédure PPrrooccBB(()) pourra voir et utiliser cette variable ? Cela dépend de ce que l’on appelle la portée de la variable Note : en fait ceci est une simplification du concept de portée car la portée d'une variable peut également dépendre de sa position dans la classes, ainsi que de plusieurs autres paramètres que nous détaillerons lorsque nous aborderons la création de classes. Pour l'instant, considérons seulement que la portée d'une variable définit sa visibilité par rapport à d'autres éléments de code. Regardons maintenant comment la manière dont les valeurs des variables sont stockées en mémoire.

33

Page 34: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.2 Représentation en mémoire Les ordinateurs utilisent pour un système de notation en bits pour stocker des valeurs temporairement dans la mémoire vive ou RAM de l’ordinateur. Ceci veut dire que, quelle que soit la valeur et le type de données que l’on souhaite stocker dans la mémoire vive, celle-ci pourra toujours être décrite sous la forme d’une suite de bits. Examinons tout d’abord comment fonctionne la notation binaire (sous forme de bits) : Prenons l’exemple du chiffre 2277. En notation binaire, ce chiffre vaut 1111001111, chaque nombre représentant une puissance de 22. Le diagramme suivant nous montre comment le chiffre 2277 est représenté en base 1100 et en notation binaire :

Base 10 En base 1100, chaque chiffre (22 et 77) représente une puissance de 1100. Pour trouver quel chiffre est représenté par la « suite de nombre en base 1100 », on multiplie chaque nombre par la puissance de 10 correspondant à sa position et l’on additionne tous les chiffres ainsi obtenus :

(7 * 100) + (2 * 101) = 27

107 106 105 104 103 102 101 100

10 000 000 1 000 000 1 00 000 10 000 1000 100 10 1

0 0 0 0 0 0 2 7

Notation Binaire En notation binaire (ou base 22), chaque chiffre représente une puissance de 22. Pour calculer quel chiffre est représenté par la « suite de nombre en base 22 » », on multiplie chaque nombre par la puissance de 22 correspondant à sa position et l’on addition tous les chiffres ainsi obtenus : (1 * 24) + (1 * 23) + (1 * 21) + (1 * 20) = 27

27 26 25 24 23 22 21 20

128 64 32 16 8 4 2 1

0 0 0 1 1 0 1 1

On constate d’après le diagramme suivant que le plus grand nombre que nous pouvons stocker sur 8 bits est 255 (ou 11111111 en notation binaire).

27 26 25 24 23 22 21 20

128 64 32 16 8 4 2 1

1 1 1 1 1 1 1 1

En effet : (1*20)+(1*21)+(1*22)+(1*23)+(1*24)+(1*25)+(1*26)+(1*27) = 255 Mais nous n’avons évoqué ici que le cas des nombres entiers positifs. Comment serait par exemple stocké le chiffre négatif –27 ?

34

Page 35: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Types numériques signés et non-signés Ce problème est résolu en réservant un bit pour stocker le signe, avec une valeur de 1 pour le signe Plus et une valeur de 0 pour le signe Moins, comme démontré dans le tableau ci-dessous :

Signe 26 25 24 23 22 21 20

+ ou - 64 32 16 8 4 2 1

On remarque que l’étendue des chiffres que nous pouvons stocker sur 8 bits va maintenant de –128 à +127. Il faut donc distinguer, pour les valeurs numériques les types de données « signés » et les types de données « non-signés ». Les types signés réservent un de leurs bits pour stocker le signe, alors que les types non-signés n’ont pas de bits réservés pour le signe. Par exemple voici les bornes minimales et maximales pour une variable numérique sur 8 bits (appelé également octet ou Byte) signée et non signée :

Type de variable Borne Min Borne MaxSignée -128 +127 Non-Signée 0 255

Un procédé similaire est utilisé pour stocker des nombres décimaux (i.e. un bit est réservé pour stocker l’emplacement de la virgule)

Chaînes de caractères (Strings) Il va de soi que l’on peut vouloir stocker dans la mémoire des informations non-numériques, par exemple des chaînes de caractères. Regardons maintenant comment sont représentées en mémoires ces chaînes de caractères : Supposons donc que nous voulions stocker dans la mémoire la chaîne de caractères « abcde » Les ordinateurs ne comprennent que les valeurs numériques. Il n’est donc pas possible de stocker directement les lettres dans la mémoire. Au lieu de cela, nous allons stocker dans la mémoire l’équivalent numérique de chacune des lettres de la chaîne de caractères. On utilise pour cela la classification standard ASCII (American Standard Code for Information Interchange) ou encore la classification UNICODE. Dans le standard ASCII, chaque lettre occuppe un octet et dans le standard UNICODE, chaque lettre occuppe deux octets (la classification UNICODE a été définie pour permettre de stocker tous les caractères existant dans toutes les langues, ce qui explique pourquoi stocker un caractère UNICODE prend deux octets alors que l'on en prend q'un en ASCII).

35

Page 36: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Le problème des chaînes de caractères est donc résolu de cette manière. Pour chaque caractère d’une chaîne, on va stocker son équivalent numérique dans un octet ou deux octets de données.

36

Page 37: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.3 Déclaration de variables Pour déclarer une variable en C#, il suffit de spécifier son nom et son type comme suit :

<<ttyyppee>> <<nnaammee>>;; par exemple : int monEntier; // déclare un entier sur 32 bits non-signé

Toute variable doit être initialisée avant son utilisation. Une fois la variable mmoonnEEnnttiieerr déclarée, nous pouvons affecter une valeur à la variable en utilisant l'opérateur d'affectation == :: monEntier = 10; Nous pouvons également déclarer la variable et initialiser sa valeur en même temps avec la syntaxe suivante : int monEntier = 10;

Si nous déclarons et initalisons plusieurs variables dans une seule instruction, les variables seront toutes de même type : int monEntier1 = 10, monEntier2 = 20;

Pour déclarer des variables de types différents, nous devons utiliser des instructions séparées; n'affectez pas des types de données différents dans une ligne de déclaration de plusieurs variables int x = 10; // déclaration correcte int y = 20; // déclaration correcte bool z = true; // déclaration correcte int x = 10, y = 20; // déclaration correcte de deux int int x = 10, z = true // ATTENTION : incorrect !!

37

Page 38: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.4 Initialisation de variables L'initialisation de variables montre l'accent mis sur la sécurité dans C#. En bref, le compilateur C# exige que toute variable soit initialisée avec une valeur de départ avant que le programmeur puisse s'y référer dans une opération. Le compilateur C#, qui est très strict, traite les violations de ce principe comme des erreurs. Ceci empêche de récupérer par inadvertance dans la mémoire des valeurs résiduelles provenant d'autres programmes. La langage C# utilise deux méthodes pour s'assurer que les variables sont initialisées avant leur utilisation :

• les variables correspondant à des champs dans une classe ou dans une structure sont remises à zéro par défaut au moment de leur création si elle ne sont pas initialisées

• les variables qui sont locales pour une méthode doivent être explicitement

initialisées dans le code préalablement à toute instruction utilisant leur valeur. Dans ce cas, il n'est pas nécessaire que l'initialisation ait lieu au moment où la variable est déclarée. Toutefois, le compilateur vérifiera tous les passages possibles par la méthode et signalera une erreur s'il détecte une possibilité quelconque d'utilisation d'une variable locale avant son initialisation.

NB: oublier d'initialiser une variable avant de l'employer dans une expression est une erreur très commune chez les débutants en C#. Un bon moyen mnemotechnique pour se souvenir qu'il faut initialiser les variables avant usage est de penser que si on ne le fait pas, la variable peut "pointer" n'importe où dans la mémoire (par exemple sur une zone déjà occupée par une autre variable dans l'application en cours ou même dans une autre application). Quoi qu'il en soit, le compilateur C# nous signale ces erreurs lors de la compilation et il est donc facile de les corriger.

38

Page 39: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.5 Nommage des variables Les noms de variables sont soumis à quelques règles et ne peuvent comporter n'importe quelle séquence de caractères. En pratique ce n'est pas très contraignant car le système de nommage adopté par C# laisse une grande liberté aux programmeurs. Les règles de bases pour le nommage des variables C# sont les suivantes :

- le premier caractère d'un nom de variable doit être une lettre, un arobase ("_") ou un ampersand ("@").

- les caractères suivants ne peuvent être que des lettres, des arobases ou des chiffres.

- aucun espace n'est autorisé.

- Il convient de ne pas nommer une variable (ou un quelconque élément) du même nom

qu'un mot-clé du langage C#.

- En raison des possibilité d'interopérabilité entre langages, si on veut qu'un assemblage soit dit "CLS – Compliant" (soit-dit se 'pliant aux règles du CLS'), il faut également éviter d'utiliser les mots-clés d'autres langages comme VB.NET.

NB : pour une référence complète de tous les mot-clés du langage C# et de tous les mots-clés de VB.NET, consultez l'annexe "Mots-clés du langage". Par ailleurs et comme énoncé plus haut dans ce chapitre, des règles et conventions de nommage en fonction de divers critères (but, portée, accessibilité) sont décrits dans l'annexe de ce support nommée "Conventions de codage", ainsi que dans le document "C# Coding Standards", téléchargeable à l'adresse suivante : http://www.componentware.net/idesign/download/IDesign CSharp Coding Standard.zip

39

Page 40: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.6 Portée des variables Définition : La portée d'une variable est la zone de code à partir de laquelle la variable est accessible. En général, la portée d'une variable est définie selon les règles suivantes :

- Un champ (également connu sous le nom de variable membre) d'une classe est visible aussi longtemps que la classe qui le contient est dans la portée (il en est de même en C++ et en Java)

- Une variable locale est visible jusquà ce qu'un accolade fermante indique la fin du bloc

d'instructions ou de la méthode dans laquelle elle a été déclarée.

- Une variable locale déclarée dans une boucle ffoorr, wwhhiillee ou similaire est visible dans le corps de cette boucle. Les programmeurs CC++++ auront remarqué que ce comportement est identique à celui de la norme ANSI pour CC++++.

Exemple using System; namespace CSharp.Introduction { public class TestPortee { public static void Main() { for (int i = 0; i < 10; i++) { Console.WriteLine(i); } // la variable i sort de portée ici // on peut déclarer une autre variable i car il n'existe pas // d'autre variable de même nom dans la portée for (int i = 9; i >= 0; i--) { Console.WriteLine(i); } // la variable i sort de portée ici } } }

Ce code affiche les nombres de 0 à 9, puis les nombres de 9 à 0 avec deux boucles ffoorr. On note que nous avons déclaré la variable i deux fois au sein de la même méthode. Ceci est possible car la variable i est déclarée dans deux boucles séparées, de sorte que chaque variable i est une variable locale dans sa propre boucle.

40

Page 41: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Cet autre exemple est incorrect et nous obtiendrons une erreur à la compilation : using System; namespace CSharp.Introduction { public class TestPortee { public static void Main() { int j = 20; for (int i = 0; i < 10; i++) { int j = 30; // INCORRECT : croisement de portées } } } }

Différences entre champs et variables locales Dans certaines circonstances, nous pouvons distinguer deux variables de même nom et de portées indentiques. En fait, C# fait une différence fondamentale (que nous étudierons en détail plus loin dans ce support) entre les variables déclarées au niveau du type (champs) et les variables déclarées dans des méthodes (variables locales). Si nous examinons le code suivant : public class TestPortee2 { static int j = 20; // ici j est un champ statique de la classe public static void Main() { for (int i = 0; i < 10; i++) { int j = 30; // ici j est une variable locale à Main() Console.WriteLine(j); } } }

Ce code est compilé sans problème ( et imprime 10 fois "30") malgré la présence de deux variables j dans la portée de la méthode Main() : la variable j définie comme un champ statique de la classe ne sort de portée que lorsque la classe est détruite, et la variable j définie dans le corps de la boucle dans la fonction Main(). Comment ferions nous pour nous référer depuis l'intérieur de la boucle à la variable de niveau classe ? Ici nous souhaitons donc accéder à un champ statique de la classe depuis une méthode statique. Il faut utiliser la syntaxe NNoommCCllaassssee..NNoommCChhaammpp.

41

Page 42: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Si nous modifions donc le code comme suit, le résultat de l'éxécution de ce programme sera l'impression de 10 fois la valeur 20. public class TestPortee2 { static int j = 20; // ici j est un champ statique de la classe public static void Main() { for (int i = 0; i < 10; i++) { int j = 30; // ici j est une variable locale à Main() Console.WriteLine(TestPortee2.j); } } }

3.7 Constantes Une constante est une variable dont la valeur ne peut pas être modifiée durant toute sa durée de vie. Le fait d'ajouter à une déclaration de variable le préfixe ccoonnsstt (lorsqu'elle est déclarée et initialisée) transforme cette variable en constante. Par exemple const int a = 100;

Les constantes possèdent les caractéristiques suivantes :

- Elles doivent être initialisées lorsqu'elles sont déclarées. - La valeur d'une constante doit être calculable lors de la compilation - Les constantes sont implicitement statiques, cependant il n'est pas permis d'utiliser le

modificateur ssttaattiicc pour déclarer une constante. L'utilisation de constantes dans le code rend celui-ci plus modulaire et plus facile à maintenir. Par exemple, plutôt que d'utiliser des "nombres magiques" à plusieurs emplacements différents du code, une constante nous permet d'avoir un endroit centralisé pour définir la valeur. Par la suite, toute modification de la valeur de la constante se répercutera dans toutes les méthodes faisant appel à cette constante. Ceci est bien sûr un gage de souplesse et les programmeurs sont encouragés à utiliser des constantes pour définir toutes les valeurs constantes dans le code. Note: Plus loin dans ce support, nous aborderons la notion d'énumérations (qui sont des constantes fortement typées). Il est préférable d'utiliser des énumérations pour définir des jeux de valeurs constantes se référant à un même sujet. Ceci sera expliqué en détail dans la section consacrée aux énumérations. Pour l'instant, utilisez des constantes quand nécessaire

42

Page 43: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4 Les types de données dans C#

4.1 Types "Valeur" et Types "Référence" Le langage C# fait la distinction entre deux catégories de types de données :

- Les types "Valeur" - Les types "Référence"

La syntaxe des types valeurs et référence sera étudiée en détail dans les prochaines sections et pendant toute la durée du cours. D'un point de vue conceptuel, la différence entre ces deux familles de types de données est que les types valeurs stockent directement leur valeurs, alors que les types référence stockent une référence vers la valeur (c'est-à-dire qu'ils ne contiennent pas la valeur mais en fait l'adresse à laquelle est stockée cette valeur en mémoire). Les types sont stockés en mémoire à différents emplacements :

- Les types valeur sont stockés dans une zone appelée "pile" - Les types référence sont stockés dans une zone appelée "tas managé"

Il est très important de savoir distinguer les différences fonctionnelles entre un type valeur et un type référence, en raison principalement des différences de comportement de ces deux familles de types quand on leur affecte des valeurs.

Exemple d'affectation à un type valeur Prenons pour l'exemple deux variables de type iinntt. Le type iinntt est un type valeur, ce qui implique comme précedemment indiqué que les variables de ce type stockent directement leur valeurs en mémoire. int i = 10; int j = i ;

Le code ci-dessus utilisera donc deux emplacements distincts en mémoire : un pour ii et un pour jj. Si plus loin dans le code nous exécutons la ligne suivante : j = 50;

Cela n'affectera que la valeur de jj et non la valeur de ii. La variable ii vaudra toujours 1100 et la variable jj vaudra 5500.

Exemple d'affectation à un type Référence Imaginons pour cet exemple que nous disposons d'une classe TTeessttCCllaassss. Cette classe posséderait un champ de type int nommé vvaalluuee. Regardons maintenant la différence des effets exercés par l'affectation en examinant le code suivant :

43

Page 44: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

TestClass x; TestClass y; x = new TestClass(); // Création d'une instance de TestClass x.value = 10; // affectation de la valeur 30 au membre value. y = x; // ici y POINTE SUR LE MEME OBJET QUE X ! Console.WriteLine(y.value); // affichage de la valeur de y.value 10 y.value = 20; Console.WriteLine(x.value); // affichage de la valeur de x.value 20

Il existe dans ce code un seul objet TTeessttCCllaassss : xx et yy pointent toutes deux vers l'emplacement mémoire contenant cet objet (on peut dire qu'ils font tout deux "référence" au même emplacement mémoire). Comme xx et yy sont des variables de type référence, la déclaration de chacune de ces variables réserve simplement une référence; elle n'instancie pas un objet du type donné. C'est la raison pour laquelle, lorsque l'on modifie yy..vvaalluuee, on modifie également xx..vvaalluuee. Note : cela équivaut à déclarer un pointeur en C++ ou une référence d'objet en VB : en aucun cas un deuxième objet n'est créé. Puisque xx et yy se réfèrent au même objet, toutes les modifications effectuées sur xx affecteront yy (et vice-versa). En conséquence, le code ci-dessus affichera la valeur 1100 puis la valeur 2200 ! Si une variable est de type référence, il est possible d'indiquer qu'elle ne se réfère à aucun objet en lui affectant explicitement la valeur nnuullll.

Conclusion Types Valeur En C# les types de données de base comme bbooooll ou lloonngg sont des types valeur. Autrement dit, si nous déclarons une variable bbooooll et lui affectons la valeur d'une autre variable bbooooll, nous aurons deux variables bbooooll séparées en mémoire. Si par la suite nous modifions la valeur de la variable originale bbooooll, la valeur de la seconde variable bbooooll ne sera pas modifiée. On dit que ces types sont copiés par valeur Types Référence La plupart des types C# plus complexes, y compris les classes que nous déclarons, sont de type référence. Ils sont alloués sur le tas, ont une durée de vie qui peut s'étaler sur plusieurs appels de fonctions, et sont accessibles via un ou plusieurs alias. Le CLR (Common Language RunTime) implémente un algorithme élaboré pour détecter les variables de type référence qui sont encore accessible mais devenues orphelines. Périodiquement, le CLT "nettoie" la mémoire en détruisant les objets orphelins et rend au système d'exploitation la mémoire que ces objets occuppaient. Cette opération de nettoyage s'effectue grâce au "ramasse-miettes" (ou GGaarrbbaaggeeCCoolllleeccttoorr). Il n'est pas possible de prédire quand le ramasse-miettes va se mettre en action pour réclamer la mémoire qui n'est plus utilisée. On appelle cette manière de nettoyer la mémoire la finalisation non-déterministe. Nous étudierons en détail le mécanisme de nettoyage et ses implications dans le chapitre traitant des constructeurs et destructeurs des classes. Performances

44

Page 45: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

En définissant les types "primaires" comme iinntt et bbooooll comme des types valeur et les types de plus grande taille contenant de nombreux champs (comme la plupart des classes) comme des types référence, C# assure de hautes performances.

45

Page 46: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.2 Types du Common Type System Les types de base prédéfinis reconnus par la langage C# ne sont pas intrinsèques au langage mais sont en fait des traductions de types "génériques" appartenant au Framework .net. Ceci permet en fait que chaque langage du Framework possède ses propres noms pour ses types de données, mais, "derrière les fagots", c'est toujours un type standard du Framework qui est déclaré. Par exemple, lorsque nous déclarons en C# une variable de type iinntt, c'est en réalité une instance du type CTS SSyysstteemm..IInntt3322 du framework qui est déclarée. Passons maintenant en revue les types définis en C#. Nous allons énumérer chaque, type avec sa définition et le type CTS .net correspondant. C# possède quinze types prédéfinis :

- 13 types Valeur - 2 Types Référence

4.3 Types Valeur prédéfinis Les types Valeur prédéfinis représentent tous des types primaires, tels que les nombres entiers ou à virgule flottante, les caractères (attention : pas les chaînes), et les types booléens.

Types d'entiers C# propose les huit types d'entiers suivants :

Nom Type CTS Description Plage (min/max) ssbbyyttee SSyysstteemm..SSbbyyttee Entier signé sur 8 bits --2277 :: 2277 -- 11

sshhoorrtt SSyysstteemm..IInntt1166 Entier signé sur 16 bits --221155 :: 221155 -- 11

iinntt SSyysstteemm..IInntt3322 Entier signé sur 32 bits --223311 :: 223311 -- 11

lloonngg SSyysstteemm..IInntt6644 Entier signé sur 64 bits --226633 :: 226633 -- 11

bbyyttee SSyysstteemm..BByyttee Entier non-signé sur 8 bits 00 :: 2288 -- 11

uusshhoorrtt SSyysstteemm..UUiinntt1166 Entier non-signé sur 16 bits 00 :: 221166 –– 11

uuiinntt SSyysstteemm..UUiinntt3322 Entier non-signé sur 32 bits 00 :: 223322 –– 11

uulloonngg SSyysstteemm..UUiinntt6644 Entier non-signé sur 64 bits 00 :: 226644 –– 11 Note: Le type Byte est le type standard sur 8 bits donnant uneplage de valeur de 0 à 255 compris. C# met l'accent sur la sécurité des types en considérant le type bbyyttee et le type cchhaarr comme distincts (alors qu'ils représentent la même plage de valeurs). Dans du code, toute conversion entre ces deux types doit être explicitement demandée. En outre, contrairement aux autres membres de la famille des entiers, le type bbyyttee est non-signé par défaut. Sa version signée porte un nom spécial : ssbbyyttee. S'il existe une ambiguité quelconque sur la nature d'un entier iinntt, uuiinntt ou lloonngg, il est remplacé par défaut par iinntt. Pour spécifier à quel type d'entier la valeur doit être associée, nous pouvons attacher l'un des caractères suivants au nombre : uint ui = 1234U; long l = 1234L; ulong ul = 1234UL;

46

Page 47: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Types de nombres en virgule flottante Voici les deux types de données C# en virgule flottante :

Nom Type CTS Description Plage (min/max) ffllooaatt SSyysstteemm..SSiinnggllee Virgule flottante sur 32 bits

simple précision ++//-- 11,,55 xx 11004455 àà ++//-- 33,,44 xx 11003388

ddoouubbllee SSyysstteemm..DDoouubbllee Virgule flottante sur 32 bits double précision

++//-- 55,,00 xx 1100332244 àà ++//-- 11,,77 xx 1100330088

Le type ffllooaatt comporte 7 chiffres significatifs après la virgule. Le type ddoouubbllee comporte 15 chiffres significatifs après la virgule. Le type de données ffllooaatt permet de manipuler des nombres en virgule flottante pour lesquels une précision normale est requise. Le type de données ddoouubbllee est plus volumineux que ffllooaatt mais il offre une précision accrue derrière la virgule (sur 15 chiffres) Si nous codons en "dur" un nombre décimal (comme 15,4) dans le code, le compilateur suppose par défaut que nous souhaitons définir une valeur de type ddoouubbllee. Pour indiquer que nous voulons une valeur de type ffllooaatt, il faut lui ajouter le suffixe "F" (ou "f"). float f = 15,4F;

Type Decimal Le type ddeecciimmaall comporte 28 chiffres significatifs après la virgule.

Nom Type CTS Description Plage (min/max) ddeecciimmaall SSyysstteemm..DDeecciimmaall Virgule flottante sur 128 bits

simple précision ++//-- 11,,00 xx 1100--2288 àà ++//-- 77,,99 xx 11002288

Le type ddeecciimmaall est principalement dédié aux calculs financiers. Le mode d'utilisation des 28 chiffres significatifs offert par le type ddéécciimmaall dépend de vous. En d'autres termes, nous pouvons suivre de petits montants en €uros avec une très grande précision au niveau des fractions de centimes, ou bien définir de grands montants avec une partie décimale arrondie. Pour spécifier q'une nombre est de type ddéécciimmaall, plutôt que de type ddoouubbllee ou ffllooaatt, nous pouvons lui attribuer le suffixe "M" (ou "m"), comme ceci. decimal d = 12.30M;

47

Page 48: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Type bool (Booléen) Le type bbooooll de C# contient soit la valeur ttrruuee soit la valeur ffaallssee.

Nom Type CTS Description Valeurs admises bbooooll SSyysstteemm..BBoooolleeaann booléen ttrruuee // ffaallssee Il est important de noter qu'il est impossible de convertir implicitement les valeurs de type bbooooll en entiers (comme cela est possible avec d'autres langages). Si une variable (ou le type renvoyé par une fonction) est de type bbooooll nous ne pourrons utiliser que les valeurs ttrruuee ou ffaallssee.

Type Char (caractère) Pour stocker la valeur d'un caractère, C# propose le type cchhaarr.

Nom Type CTS Description Valeurs admises cchhaarr SSyysstteemm..CChhaarr un seul caractère uunn sseeuull ccaarraaccttèèrree

ssuurr 1166 bbiittss ASCII et Unicode : Bien que 8 bits soient suffisants pour encoder chaque caractère de l'anglais, ils ne suffisent pas pour encoder chaque caractère des systèmes alphabétiques utilisant une gamme de symboles plus vaste (comme le chinois par exemple). Dans un souci d'internationalisation, le monde informatique abandonne progressivement l'habitude de stocker les caractères sur 8 bits (ASCII) pour se tourner vers le schéma Unicode normalisé sur 16 bits. A noter qu'ASCII est un sous-ensemble d'Unicode. Les expressions littérales de type cchhaarr doivent être placées entre quotes à la différence des chaînes de caractères ou ssttrriinngg qui doivent être placées entre guillemets doubles. char c = 'a';

Il est possible de représenter les expressions char sous forme littérale, mais également sous forme de valeurs Unicode hexadécimales à 4 chiffres (par exemple '\\uu00004411''), sous forme de valeurs entières avec un transtypage (par exemple ((cchhaarr))6655 ) ou sous forme hexadécimale ( par exemple ''\\xx00004411''), ou encore à l'aide d'une séquence d'échappement (escape sequence). La liste des caractère d'échappement est diponible dans l'annexe de ce support nommée "caractères d'échappement"

48

Page 49: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.4 Types Référence prédéfinis C# prend en charge deux types valeurs prédéfinis :

Nom Type CTS Description oobbjjeecctt SSyysstteemm..OObbjjeecctt Le type racine à partir duquel tous les

types dérivent (y compris les types valeurs mais pas directement)

ssttrriinngg SSyysstteemm..SSttrriinngg Chaîne de caractères Unicode.

Type object En C#, tout est objet. Voici une vérité que nous découvrirons au fur et à mesure de notre apprentissage du language. De nombreux langages et hiérarchies de classes fournissent un type racine, à partir duquel dérivent tous les autres objets de la hiérarchie. En C# le type object est le type racine de tous les types de données. Tous les types de données intrinsèques et les types définis par l'utilisateur dérivent de object. C'est une des caractéristiques clé de C#, qui le distingue de langages comme VB6 ou C++, et le rapproche de Java. Comme tous les types dérivent implicitement de la classe SSyysstteemm..OObbjjeecctt, nous pouvons utiliser le type oobbjjeecctt dans un boucle but :

- pour établir un lien à un objet d'un sous-type particulier. Par exemple, nous verrons plus loin comment utiliser le type oobbjjeecctt pour "emboiter" (boxing) un type valeur stocké sur la pile et le déplacer sur le tas.

- Pour implémenter un certain nombre de méthodes génériques que tous les éléments de tous les

types de données posséderont. C'est le cas des méthodes EEqquuaallss(()), GGeettHHaasshhCCooddee et TTooSSttrriinngg(()). Les classes définies par l'utilisateur peuvent avoir besoin de fournir des implémentations de remplacement de certaines de ces méthodes à l'aide de la technique orientée objet appelée "substitution". Quand nous nous substituons la méthode TTooSSttrriinngg(()) par exemple, nous dotons notre classe d'une méthode destinée à fournir une représentation littérale personalisée d'elle-même. Si nous ne fournissons pas notre propre implémentation des ces méthodes dans nos classes, le compilateur appellera les méthodes génériques de la classe oobbjjeecctt, ce qui peut être pratique dans de nombreux cas.

PAS DE CONFUSION ! nous avons dit plus haut que tous les types dérivent de SSyysstteemm..OObbjjeecctt. Pour autant, il ne faut pas en déduire que tous les types de données intrinsèques se comportent comme des objets !!. Il s'agit ici de l'implémentation interne de C#. En réalité, tous les types référence dérivent directement de SSyysstteemm..OObbjjeecctt, et tous les types valeur dérivent indirectement de SSyysstteemm..VVaalluueeTTyyppee qui lui-même dérive de SSyysstteemm..OObbjjeecctt.

49

Page 50: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Type string C# fournit son propre type ssttrriinngg. Avec ce type, les opération comme la concaténation ou la copie de chaînes de caractères (et bien d'autres opérations) sont d'une grande simplicité : string s1 = "bonjour "; string s2 = "tout le monde !"; string s3 = s1 + s2; // s3 vaut "Bonjour tout le monde !"

Nota Bene : En dépit de ce style d'affectation, la classe CTS SSyysstteemm..SSttrriinngg est bien un type référence ! En coulisses, un objet ssttrriinngg, est alloué au tas et non à la pile. Quand nous affectons une valeur littérale à une autre chaîne, nous obtenons deux références à la même chaîne en mémoire. Cependant, si nous modifions l'une de ces chaînes, la modification a pour résultat la création en mémoire d'un nouvel objet ssttrriinngg, en laissant l'autre chaîne inchangée. Exemple : using System; namespace CSharp.DataTypes { public class StringExemple { public static void Main() { string s1 = "toto"; string s2 = s1; Console.WriteLine("s1 vaut :" + s1); Console.WriteLine("s2 vaut :" + s2); s1 = "titi"; Console.WriteLine("s1 vaut maintenant :" + s1); Console.WriteLine("s2 vaut maintenant :" + s2); } } }

la sortie est la suivante : s1 vaut : toto s2 vaut : toto s1 vaut maintenant : titi s2 vaut maintenant : toto En d'autres termes, la modification de la valeur s1 n'a pas d'effet sur la valeur de s2 contrairement à ce que nous pouvions imaginer avec un type référence !! Que se passe-t-il en réalité ? Quand ss11 est initialisée avec la valeur "uunnee cchhaaiinnee", un nouvel object est alloué sur le tas. Quand ss22 est initialisée, la référence point sur le même objet et a donc également la valeur "uunnee cchhaaîînnee".

50

Page 51: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Cependant, quand nous modifions la valeur de ss11, au lien du remplacement de la valeur d'origine, un nouvel objet est créé sur au tas avec la nouvelle valeur. La variable ss22 pointe vers l'objet original et sa valeur reste inchangée. Ceci est dû au fait que le type SSyysstteemm..SSttrriinngg est un type dit "immutable" d'une part. D'autre part l'opérateur d'égalité a été redéfini pour les variables de type ssttrriinngg de façon à comparer les valeurs et non les références (en effet, ce comportement est plus "naturel" pour les programmeurs). Chaînes littérales ou "verbatim" Les chaînes C# peuvent, comme les variables cchhaarr, contenir des séquences d'échappement Unicode et hexadécimales. Comme ces séquences démarrent par le caractère "\", nous ne pouvons utiliser ce caractère une seule fois dans une chaîne. En conséquence (par exemple pour stocker un chemin de fichier) il nous faut mettre deux caractères "\" pour en représenter un : string filePath = "C\\Dev\\TestString.cs";

On peut s'affranchir de cette contrainte car C# nous fournit une alternative : les chaînes littérales ou "verbatim": en préfixant la valeur littérale de la chaîne par le caractère "@" : string filePath = @"C\Dev\TestString.cs";

lorsqu'une chaîne est préfixée avec le caractère "@" tous ses caractères sont traités comme tels et non comme des séquences d'échappement. Ceci nous permet entre autres choses d'insérer des retours à la ligne dans les expressions littérales : string maChaineSurDeuxLignes = "Je suis une chaîne avec un retour chariot";

la valeur de la chaîne sera alors : JJee ssuuiiss uunnee cchhaaîînnee aavveecc uunn rreettoouurr cchhaarriioott

51

Page 52: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5. opérateurs et expressions Nous avons maintenant vu comment déclarer et initialiser des variables. Etudions à présent la façon de les manipuler. C# comporte un certain nombre d'opérateurs (dont par exemple l'opérateur d'affectation = que nous avons déjà évoqué dans ce support). La combinaison d'operateurs avec des variables avec des variables et des valeurs littérales permet de créer des expressions, qui sont les composantes de base des calculs.

5.1 Différents types d'opérateurs C# prend en charge les opérateurs décrits dans le tableau suivant. Quatre d'entre eux (ssiizzeeooff, **, -->>, et &&)) ne sont disponibles que dans du code non-sécurisé (ou "unsafe code"), c'est-à-dire du code qui échappe à la vérification de la sécurité de types de C#. Catégorie d'opérateurs Opérateurs Arithmétique ++ -- ** // %%

Logique && || ^̂ ~~ &&&& ||||

Concaténation de chaînes ++

Incrément et décrément ++++ ----

Déplacement de bits <<<< >>>>

Comparaison ==== !!== << >> <<== >>==

Affectation == ++== --== **== //== %%== &&== ||== ^̂== <<<<== >>>>==

Accès aux membres (pour objets et structures) ..

Indexation (pour tableaux et indexeurs) [[]]

Transtypage (())

Conditionnel (opérateur ternaire) ??::

Création d'objets nneeww

Informations de type ssiizzeeooff ((nnoonn ssééccuurriisséé)) ttyyppeeooff iiss aass

Contrôle d'exception de dépassement de pile cchheecckkeedd uunncchheecckkeedd

Indirection et adresses ** -->> && ((nnoonn ssééccuurriissééss))

52

Page 53: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.2 Opérateurs et raccourcis Le tableau suivant donne une liste complète d'opérateurs disponibles en C#. Raccourci de l'opérateur Equivalent à xx++++ ,, ++++xx xx == xx ++ 11 xx---- ,, ----xx xx == xx –– 11 xx ++== yy xx == xx ++ yy xx --== yy xx == xx –– yy xx **== yy xx == xx ** yy xx //== yy xx == xx // yy xx %%== yy xx == xx %% yy xx >>>>== yy xx == xx >>>> yy xx <<<<== yy xx == xx <<<< yy xx &&== yy xx == xx && yy xx ||== yy xx == xx || yy xx ^̂== yy xx == xx ^̂ yy L'opérateur d'incrémentation ++++ et de décrémentation –– se placent soit avant l'expression (ils sont alors préfixés) soit après l'expression (ils sont alors suffixés). Les expressions xx++++ et ++++xx sont toutes deux équivalentes à : xx == xx ++ 11 mais leurs comportement diffèrent. Occupant une ligne, ils sont équivalents et correspondent à l'instruction xx == xx ++ 11. La différence apparaît lorsqu'ils sont utilisés dans des expressions : • ++++xx incrémente la valeur de xx avant que l'expression soit évaluée; en d'autres termes, xx est d'abord

incrémenté, puis la nouvelle valeur de xx est utilisée dans l'expression • xx++++ incrémente la valeur de xx après que l'expression a été évaluée, ce qui fait que l'expression est

d'abord évaluée avec la valeur initiale de xx et l'incrémentation de xx se fait seulement après. L'exemple suivant montre la différence entre les deux opérateurs : int x = 5; if (++x == 6) { Console.WriteLine("Cette ligne sera exécutée"); } if (x++ == 7) { Console.WriteLine("Cette ligne ne sera PAS exécutée"); }

53

Page 54: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.3 L'operateur ternaire L'opérateur ternaire ??:: est une forme abrégée de la construction iiff....eellssee. Il tient son nom du fait qu'il implique trois opérandes. Il permet d'évaluer une condition en retournant une valeur si cette condition est vraie et une autre valeur si cette condition est fausse. Syntaxe : condition ? valSiVrai : valSiFaux

Il est préférable d'utiliser cet opérateur avec modération et lui préférer dans la plupart des cas des structures conditionnelles iiff....eellssee classiques. Cependant, il permet quelquefois de rendre plus concises quelques lignes de code. En voici un exemple : bool condition = true; Console.WriteLine(condition ? "Vrai" : "Faux");

Le code ci-dessus écrit "VVrraaii" dans la sortie.

5.4 Opérateurs checked et unchecked Les opérateurs cchheecckkeedd et uunncchheecckkeedd permettent de mettre en œuvre ou d'empêcher les contrôles de dépassement par le compilateur. Regardons le code suivant : byte b = 255; b++; Console.WriteLine(b.ToString());

Le type de données bbyyttee ne peut contenir que des valeurs dans la plage allant de 0 à 255. L'incrémentation de la valeur de bb avec bb++++;; déclenche donc un dépassement de pile. La manière dont le CLR traite ce problème dépend de divers paramètres dont (entre autres) les options que l'utilisateur a défini pour le compilateur. Normalement, à chaque fois que du code peut déclencher un dépassement non autorisé, il faut s'assurer d'obtenir le résultat désiré. Pour ce faire, C# nous fournir les opérateurs cchheecckkeedd et uunncchheecckkeedd. Si nous marquons un bloc de code comme cchheecckkeedd, le CLR active le contrôle de dépassement pour ce bloc et lève une exception si un dépassement survient dans ce bloc. Si nous modifions le code pour l'encadrer dans un bloc cchheecckkeedd : byte b = 255; checked {

b++; } Console.WriteLine(b.ToString());

Si nous lançons ce code, nous obtenons un message d'erreur nous indiquant qu'un exception de type SSyysstteemm..OOvveerrfflloowwEExxcceeppttiioonn s'est produite. Si nous souhaitons supprimer le contrôle de dépassement pour ce bloc de code, nous pouvons au contraire marquer le bloc comme uunncchheecckkeedd. Dans ce cas, aucune exception n'est levée, mais nous perdrons des

54

Page 55: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

données car le type bbyyttee ne peut pas contenir la valeur 256. Les bits du dépassement sont supprimés et la variable bb contiendra la valeur zéro. NB1: Vous pouvez mettre en œuvre le contrôle de dépassement pour tout votre code non marqué comme cchheecckkeedd en compilant avec l'option //cchheecckkeedd. Attention : uunncchheecckkeedd est le comportement par défaut ! En d'autres termes, cet opérateur est rarement utilisé explicitement, sauf quand il nous faut marquer quelques lignes de code comme uunncchheecckkeedd dans un grands bloc de code explicitement marqué comme cchheecckkeedd.

5.5 Opérateur sizeof Nous pouvons déterminer la taille (en octets) requise par un type valeur de la pile en utilisant l’opérateur ssiizzeeooff : unsafe { Console.WriteLine(sizeof(int)); }

5.6 Opérateur typeof L’opérateur ttyyppeeooff retourne un objet TTyyppee représentant un type spécifié. Par exemple, ttyyppeeooff((ssttrriinngg)) retourne un objet représentant le type SSyysstteemm..SSttrriinngg. C’est utile lorsque nous voulons exploiter la réflexion pour obtenir dynamiquement des informations sur un objet (notons que nous pouvons également utiliser la méthode d'instance ttyyppeeOObbjjeett..GGeettTTyyppee(())). Nous aborderons la réflexion plus loin dans ce support.

5.7 Préséance des opérateurs Le tableau suivant indique l’ordre de priorité des opérateurs C#. Les opérateurs au sommet du tableau sont ceux qui ont la priorité la plus forte (c’est à dire, ceux qui sont évalués en premier dans une expression contenant plusieurs opérateurs) : Groupe Opérateurs DDiivveerrss (()) .. [[]] xx++++ xx——nneeww ttyyppeeooff ssiizzeeooff cchheecckkeedd

uunncchheecckkeedd UUnnaaiirree ++ -- !! ~~ ++++xx ––xx ttrraannssttyyppaaggeess MMuullttiipplliiccaattiioonn // DDiivviissiioonn ** // %% AAddddiittiioonn // SSoouussttrraaccttiioonn ++ -- OOppéérraatteeuurrss ddee ddééccaallaaggee bbiinnaaiirreess <<<< >>>> RReellaattiioonnnneell << <<== >>== >> iiss aass CCoommppaarraaiissoonn ==== !!== EETT bbiinnaaiirree && OOUU bbiinnaaiirree ^̂ XXOORR bbiinnaaiirree || EETT bboooollééeenn &&&& OOUU bboooollééeenn |||| OOppéérraatteeuurr tteerrnnaaiirree ??:: AAffffeeccttaattiioonn == ++== --== **== //== %%== &&== ||== ^̂== <<<<== >>>>==

55

Page 56: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.8 Sécurité et Types Le langage intermédiaire met en œuvre la sécurité des types dans son code. Le typage fort autorise de nombreux services fournis par .NET, dont la sécurité et l’interopérabilité des langages. Comme nous pouvons nous y attendre de la part d’un langage compilé en IL, C# est également fortement typé. Entre autres, cela signifie que le type bbooooll dédié n’est pas converti automatiquement en type entier. Pour opérer une telle conversion, nous devons en faire la demande, à l’aide d’un transtypage explicite. Dans ce chapitre, nous examinerons le transtypage entre types primaires.

6. Conversions de types de données Nous avons souvent besoin de convertir des données d’un type vers un autre. Considérons le type suivant : byte value1 = 10; byte value2 = 20; byte total; total = value1 + value2; Console.WriteLine(total);

Si nous compilons ces lignes, nous obtenons le message d’erreur :

Cannot implicitly convert ‘int’ to ‘byte’

Le problème est le suivant : lorsque nous additionnons deux bbyyttee, le résultat retourné est un iinntt, et non un autre bbyyttee. Cela est dû au fait qu’un bbyyttee ne peut contenir que huit bits de données. Pour stocker ce résultat dans une variable bbyyttee, il faut la reconvertir en un bbyyttee. Cela peut se faire implicitement ou explicitement.

6.1 Conversions implicites La conversion entre types peut normalement s’effectuer de façon automatique (implicitement) uniquement si nous pouvons garantir, ce faisant, qu’elle n’affectera en aucune manière la valeur. C’est la raison pour laquelle le code précédent provoque une erreur à la compilation : en tentant une conversion d’un type iinntt en type bbyyttee, nous avons potentiellement perdu trois octets de données. Le compilateur ne le permet pas, à moins que nous lui indiquions explicitement que c’est ce que nous voulons faire ! Toutefois, si nous stockons le résultat dans un type lloonngg au lieu d’un type bbyyttee, nous n’avons aucun problème : // Ce code se compile sans problème. byte value1 = 10; byte value2 = 20; long total; total = value1 + value2; Console.WriteLine(total); Comme un type lloonngg renferme plus d’octets de données qu’un type iinntt, il n’y a pas de risque de perte de données et le code se compile sans problème.

56

Page 57: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Le tableau suivant liste les conversions de types implicites prises en charge par C# : De En

sbyte short, int, long, float, double, decimal

byte short, ushort, int, uint, long, ulong, float, double, decimal

short int, long, float, double, decimal

ushort int, uint, long, ulong, float, double, decimal

int long, float, double, decimal

uint long, ulong, float, double, decimal

long, ulong float, double, decimal

float double

char ushort, int, uint, long, ulong, float, double, decimal

Nous ne pouvons effectuer des conversions implicites que d’un entier de petite taille vers un entier de plus grande taille, et non l’inverse. Nous pouvons aussi passer d’une valeur entière à une valeur en virgule flottante. Outre des conversions entre types de même taille, par exemple de iinntt/uuiinntt en ffllooaatt et de lloonngg/uulloonngg en double, nous avons également la possibilité d’effectuer une conversion inverse de lloonngg/uulloonngg en ffllooaatt. Nous pouvons perdre quatre octets de données dans l’opération car le type ffllooaatt résultant est moins précis qu’un type ddoouubbllee. Le compilateur considère cela comme une erreur acceptable, l’ordre de grandeur de la valeur n’en étant pas affecté. Nous pouvons également affecter une variable non signée à une variable signée à condition que les limites de valeur du type non signé rentrent dans les limites de la variable signée.

57

Page 58: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

6.2 Conversions explicites De nombreuses conversions ne peuvent être effectuées implicitement entre types. En cas de tentative de ce genre, le compilateur renvoie une erreur. Voici quelques transformations qui ne peuvent être effectuées implicitement :

- de iinntt en sshhoorrtt (risque de perte de données) ; - de iinntt en uuiinntt (risque de perte de données) ; - de uuiinntt en iinntt (risque de perte de données) ; - de ffllooaatt en iinntt (perte de tout ce qui se trouve après le point décimal) ; - de tout type numérique en cchhaarr (risque de perte de données) ; - de ddeecciimmaall en n’importe quel type numérique, le type ddeecciimmaall étant structuré en interne

différemment des entiers et des nombres en virgule flottante. Cependant, nous pouvons effectuer explicitement de telles transformations en utilisant le transtypage. Lorsque nous transtypons un type dans un autre, nous forçons délibérément le compilateur à effectuer la transformation. Un transtypage ressemble à ceci : long val = 30000; int i = int(val);

Nous indiquons le type que nous transtypons en plaçant le type transtypé entre parenthèses avant la valeur à modifier. Pour les programmeurs en C, cette syntaxe de transtypage est habituelle. Cesl pérations sont potientiellement dangereuse : même un transtypage de lloonngg en iinntt peut entraîner des problèmes si la valeur initiale dépasse la valeur maximale d'un iinntt. long val = 3000000000; int i = (int)val; // transtypage invalide : valeur max de int : 2147483647

Dans le code précédent, nous n'obtenons pas d'erreurs explicite, mais nous n'avons pas non plus la valeur attendue dans la variable iinntt, nous obtenons : --11229944996677229966 En fait, il ne faut jamais supposer a priori que le transtypage fournira le résultat attendu. C# propose un opérateur cchheecckkeedd qui permet de tester si une opération provoque un dépassement. Nous pouvons utiliser cet opérateur pour vérifier qu’un transtypage est sûr et forcer le runtime à lever une exception de dépassement en cas de besoin : long val = 3000000000; int i = checked((int)val); // ici une exception System.OverflowException est levée

Avec le transtypage, nous pouvons convertir la plupart des types de données d’un type dans un autre, par exemple : double prix = 25.30; int prixArrondi = (int)(price + 0.5);

Dans l'exemple ci-dessus, nous obtenons la valeur arrondie.

58

Page 59: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Cet exemple montre ce qui se passe lorsque nous convertissons un entier non signé dans le type cchhaarr : ushort c = 43; char symbol = (char)c; Console.WriteLine(symbol);

La sortie correspond au caractère ayant le code ASCII 43, à savoir le signe ++. Nous pouvons tenter tout type de transformation entre les types numériques (dont cchhaarr), aussi étonnant que cela puisse paraître. Ainsi, la conversion d’un type ddeecciimmaall en type cchhaarr fonctionne, et vice versa. Cependant, si la valeur qui résulte de l’opération de transtypage ne peut pas s’ajuster au nouveau type de données, le transtypage semble fonctionner mais le résultat n’est pas nécessairement celui attendu. Par exemple : int i = -1; char c = (char)i;

Ce transtypage ne devrait pas fonctionner car le type cchhaarr ne peut accepter de valeurs négatives. Cependant, nous n’obtenons pas d’erreur et la valeur ?? est affectée à la variable ssyymmbbooll. Pour effectuer une conversion entre un nombre et une chaîne, par exemple, nous disposons des méthodes offertes par la bibliothèque de classes de .NET. La classe object implémente une méthode TTooSSttrriinngg(()), qui a été remplacée dans tous les types .NET prédéfinis et qui retourne une représentation littérale de l’objet : int i = 10; string s = i.ToString();

Pour « parser » une chaîne afin de retrouver une valeur numérique ou booléenne, nous pouvons utiliser la méthode PPaarrssee(()) prise en compte par tous les types valeur prédéfinis : string s = "100"; int i = Int.Parse(s); Console.WriteLine(i + 50);

La méthode statique PPaarrssee lève une exception si elle n'est pas capable de convertir la chaîne.

59

Page 60: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

6.3 Boxing et un-Boxing Tous les types, aussi bien les types simples prédéfinis comme iinntt et cchhaarr que les types complexes tels que les classes et les structures, dérivent du type object. Cela signifie que nous pouvons traiter des valeurs littérales comme si elles étaient des objets : string s = 10.ToString();

Par ailleurs, les types de données de C# se divisent entre les types valeur, alloués à la pile, et les types référence, alloués au tas. Comment cela cadre-t-il avec la possibilité d’appeler les méthodes sur iinntt, si iinntt n’est rien de plus qu’une valeur sur quatre octets de la pile ? C# réalise en fait un tour de passe-passe appelé boxing (emboîtage). Boxing et un boxing (déboîtage) permettent de convertir des types valeur en types référence, et vice versa. Ces opérations s’apparentent au transtypage en ce sens que nous transtypons une valeur en type oobbjjeecctt. "Boxing" est un terme utilisé pour décrire la transformation d’un type valeur en type référence. Pour ce faire, le runtime crée une « boîte »temporaire de type référence pour l’objet sur le tas. Cette conversion peut avoir lieu implicitement, comme dans l’exemple précedent, mais elle peut aussi être effectuée manuellement : int i = 20; object o = i;

"Unboxing" (déboîtage) est le terme utilisé pour décrire le processus inverse, par lequel une valeur d’un type référence est transtypée en type valeur. Nous utilisons le terme « transtypage » ici, car cela doit être fait explicitement. La syntaxe est comparable à celle des conversions de types explicites déjà écrites : int i = 20; object o = i; int j = (int)o;

Attention : lors du déboîtage, il faut veiller à ce que la variable réceptrice de la valeur ait suffisamment d’espace pour stocker tous les octets dans la valeur déboîtée. Les types iinntt de C#, par exemple, ont une longueur de 32 bits, de sorte que le déboîtage d’une valeur lloonngg (sur 64 bits) en un iinntt entraîne une exception IInnvvaalliiddCCaassttEExxcceeppttiioonn, comme dans l’exemple suivant : long a = 333333423; object b = (object)a; int c = (int)b;

60

Page 61: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

7. Contrôle du Flux d'exécution Dans cette section, nous allons examiner le processus de fonctionnement du langage eet en particulier les instructions qui permettent de contrôler le flux d'exécution d'un programme.

7.1 Les Instruction Conditionnelles Les instructions conditionnelles permettent d'insérer des branchements dans le code selon que certaines conditions sont vérifiées ou pas ou encore en fonction de la valeur d'une expression. La langage C# possède deux structures conditionnelles : l'instruction iiff qui permet de tester si une condition est satisfaite et l'instruction sswwiittcchh qui permet de comparer une expression avec différentes valeurs et d'effectuer des actions en conséquence.

L'instruction if Pour les branchements conditionnels, C# utilise la même syntaxe pour l'instruction iiff que C et C++. Voici les différentes formes syntaxiques de l'instruction iiff : Evaluer une seule condition iiff ((ccoonnddiittiioonn)) iinnssttrruuccttiioonn;; Par exemple : if (x > 5) Console.WriteLine("x est supérieur à 5);

Si plusieurs instructions doivent être exécutées lorsque la condition est vérifiée, il faut encadrer le bloc d'instruction entre des accolades : iiff ((ccoonnddiittiioonn)) {{ iinnssttrruuccttiioonn11;; iinnssttrruuccttiioonn22;; }} Remarque : il est plus "propre" (voir annexe "conventions de codage") de toujours encadrer les instructions dépendantes d'une conditions dans un bloc d'accolades. Ne pas le faire n'est pas illégal mais peut rendre la lecture du code plus difficile. Par exemple : if (x == 0) Console.WriteLine ("X est égal à 0"); Console.WriteLine ("X peut être n'importe quelle valeur");

Dans l'exemple précédent, la ligne indiquant que "x peut être n'importe quelle valeur" s'exécutera toujours quelle que soit la valeur de xx. et ne dépendra donc pas du résultat de l'évaluation de la condition

61

Page 62: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Il aurait été plus facile de lire : if (x == 0) {

Console.WriteLine ("X est égal à 0"); } Console.Write ("ligne non dépendant du test x == 0");

Evaluer deux jeux de résultats On peut également vouloir effectuer deux actions différentes selon que la condition dans le test iiff est vérifiée ou pas. Dans ce cas, on utilise la clause eellssee des manières suivante : Pour exécuter plusieurs instructions dans chaque bloc Pour n'exécuter qu'une instruction par bloc iiff ((ccoonnddiittiioonn)) {{ iinnssttrruuccttiioonnss;; }} eellssee {{ iinnssttrruuccttiioonnss;; }}

iiff ((ccoonnddiittiioonn)) iinnssttrruuccttiioonn;; eellssee iinnssttrruuccttiioonn;;

Evaluer des jeux de résultats multiples On peut également avec la structure iiff souhaiter évaluer plusieurs conditions (et non pas seulement une condition qui est soit vraie soit fausse). Dans ce cas, on dipose de la clause eellssee iiff qui nous permet d'ajouter des conditions à tester. string reponse; reponse = Console.ReadLine(); // Lit l'entrée de l'utilisateur if (reponse.Length == 0) { Console.WriteLine("Vous n'avez pas entré de texte"); } else if (reponse.Length < 5) { Console.WriteLine("Vous avez pas entré moins de 5 caractères"); } else if (reponse.Length < 10) { Console.WriteLine("Vous avez pas entré entre 5 et 10 caractères"); } else { Console.WriteLine("Vous avez entré plus de 10 caractères"); }

Notons que la clause eellssee n'est pas obligatoire lors de l'utilisation de clauses eellssee iiff.. Le nombre de clauses eellssee iiff pouvant être ajoutées à la clause iiff initiale n'est pas limité, cependant, lorsque nous souhaiterons évaluer un grand nombre de jeux de résultats possibles différents, on utilisera (autant que possible) l'instruction sswwiittcchh.... ccaassee qui est plus lisible.

62

Page 63: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

L'instruction switch L'instruction sswwiittcchh.... ccaassee est apte est apte à sélectionner un branchement de l'exécution à partir d'un jeu de branchement mutuellement exclusifs. Cette instruction est connue des programmeurs C++ et Java. Les programmeurs VB la connaissent sous la forme presque identique de l'instruction SSeelleecctt .... CCaassee. Syntaxe de switch … case Cette instruction prend la forme d'un argument sswwiittcchh, suivi d'une série de clauses ccaassee. Lorsque l'expression de l'argument sswwiittcchh s'évalue à l'une des valeurs placées dans les clauses ccaassee, le bloc d'instructions situé immédiatement en dessous de la clause ccaassee est exécuté. Dans ce cas, nous n'avons pas besoin de mettre les instructions dépendantes d'un bloc ccaassee entre accolades, mais nous devons indiquer la fin du code de chaque clause ccaassee par le mot-clé bbrreeaakk suivi d'un point virgule. Nous pouvons également inclure dans une instruction sswwiittcchh une clause default qui sera exécutée si l'expression testée ne s'évalue à aucune des clause ccaassee. L'instruction sswwiittcchh teste ici la valeur de la variable iinnttAA (qui est de type iinntt) : switch (intA) { case 1: Console.WriteLine("intA vaut 1"); break; case 2: Console.WriteLine("intA vaut 2"); break; case 3: Console.WriteLine("intA vaut 3"); break; default: // Cas par défaut utilisé si aucun bloc case n'est exécuté Console.WriteLine("intA ne vaut ni 1 ni 2 ni 3"); break; }

Remarque : notons que les valeurs associées aux blocs ccaassee doivent être soit des valeur littérales soit des constantes mais ne peuvent pas être des variables. Fall-through Les programmeurs en C et C++ connaissant l'instruction switch avec une syntaxe un peu différente. Cependant, cette instruction est plus sûre en C#. En particulier elle interdit les conditions dites "fall trough" dans presque tous les cas. Autrement dit, si une clause ccaassee est activée en début de bloc, les clauses ccaassee suivantes ne peuvent plus être activée (à moins d'utiliser l'instruction ggoottoo) pour marquer spécifiquement la volonté d'activer une cause particulière. Le compilateur renforce cette restriction en siganalant chaque clause ccaassee non pourvue d'une instruction bbrreeaakk comme une erreur avec le message d'erreur suivant :

Control cannot fall trough from one case label ('case x') to another. Bien que le comportement "fall trough" soit désirable dans un nombre limité de situations, il est involontaire dans la majorité des cas et a pour résultat une erreur logique difficile à cerner.

63

Page 64: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Instruction goto En utilisant des instructions ggoottoo (cette approche n'est pas très structurée mais c'est quelquefois la seule approche), il est possible de simuler la fonctionnalité "fall-through" dans les instructions sswwiittcchh ccaassee. Cette approche n'est pas élégante. Le code suivant démontre la manière d'utiliser ggoottoo pour simuler un fall-through; il montre également combien le code résultant peut être "touffu" (on appelle également ce genre de code difficile à lire du code "spaghetti"). // on suppose que le pays (country) et la langue (langage) sont de type string switch (country) { case "America": CallAmericanMethod; goto case "Britain"; // Aller au bloc case "Britain" case "France": langage = "French"; break; case "Britain": langage = "English"; break; }

Il existe toutefois une exception à la règle "no fall-through" : Il est en fait possible de passer directement d'une clause ccaassee à une autre si cette clause est vide. Cela permet de traiter deux clauses ccaassee ou plus de manière identique sans faire appel à des instructions ggoottoo.. switch (country) { case "us": case "uk": case "au": langage = "English"; break; case "ca": case "fr": langage = "French"; break; }

Important : Un aspect curieux de C# est que l'ordre des clauses ccaassee n'a pas d'importance et il est même possible de placer la clause ddeeffaauulltt en premier ! Il en résulte que deux clauses ccaassee ne peuvent pas être identiques ! Cela concerne par exemple des constantes différentes mais ayant la même valeur. Ainsi, le code suivant est dont incorrect : const string england = "uk"; const string britain = "uk"; switch (country) { case england: case britain: language = "English";

64

Page 65: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

break; }

7.2 Les Boucles C# propose quatre types de boucles différentes (ffoorr, wwhhiillee, ddoo……wwhhiillee et ffoorreeaacchh) permettant de répéter l'exécution d'un bloc de code jusqu'à ce qu'un condition soit satisfaite. Les boucles ffoorr, wwhhiillee et ddoo……wwhhiillee sont pour l'essentiel indentiques à celles utilisées en C++. Nous allons examiner en détail le fonctionnement de chacune de ces boucles.

La boucle for Les boucles ffoorr de C# proposent un mecanisme d'itération qui teste si une condition est remplie avant d'effectuer une autre itération (une itération est un passage complet dans le corps de la boucle). syntaxe de la boucle ffoorr : for (intialiseur; condition; itérateur) { instruction(s) }

où :

- L'initialiseur est l'expression évaluée avant l'exécution de la première boucle (en général c'est une variable locale servant de compteur de boucle)

- La condition est l'expression vérifiée avant chaque nouvelle itération de la boucle (elle doit être

évaluée à la valeur ttrruuee pour qu'une autre itération puisse être effectuée)

- L'itérateur est une expression qui est évaluée après chaque itération, réalisant habituellement l'incrémentation du compteur de boucle). Les itérations cessent dès que la condition est évaluée à la valeur ffaallssee.

La boucle ffoorr est une boucle dite de "pre-test" car la condition de la boucle est évaluée avant que les instructions de boucle soient exécutées. La boucle ffoorr est tout à fait adaptée pour répéter une ou plusieurs instructions pendant un nombre déterminé de fois. L'exemple de code suivant est typique d'un boucle ffoorr. Ce code affiche les valeurs de 0 à 10 : for (int i = 0; i < 11; i++) { Console.WriteLine(i); }

Nous déclarons ici une variable iinntt nommée i et nous l'initialisons à zéro. Elle sera utilisée comme compteur de boucle. Nous testons immédiatement si elle est inférieure à 11. Comme cette condition s'évalue à ttrruuee, le code dans la boucle s'exécute, ce qui permet d'imprimer la valeur 0 (à la première itération bien sûr). Nous incrémentons ensuite le compteur de 1 et le processus reprend. La boucle se termine quand la variable ii a atteint la valeur 100.

65

Page 66: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

La syntaxe de la boucle for en C# est bien plus puissante que la syntaxe For…Next de VB car l'itérateur peut être n'importe quelle instruction. En VB, tout ce qu'il est possible de faire est d'ajouter ou de soustraire un nombre à la variable de contrôle de la boucle. En C# tout est permis, y compris multiplier la variable de contrôle par un autre nombre.

66

Page 67: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

La boucle while la boucle wwhhiillee est identique à la boucle wwhhiillee en C++ et en Java et à la boucle WWhhiillee……WWeenndd en VB. Comme la boucle ffoorr, la boucle wwhhiillee est une boucle de pré-test. Leur syntaxe est similaire mais la boucle wwhhiillee n'admet qu'une seule expression de condition. syntaxe de la boucle wwhhiillee : while (condition) { instruction(s) }

Contrairement à la boucle ffoorr, la boucle wwhhiillee est le plus souvent utillisée pour répéter les instructions contenues dans son bloc un nombre de fois qui n'est pas connu avant que la boucle commence. Habituellement, une instruction dans le corps de la boucle wwhhiillee définit un flag booléen à false sur une certaine itération, déclenchant ainsi la fin de la boucle, comme dans l'exemple suivant : bool condition = false; while (condition) { // cette boucle tourne jusqu'à ce que : condition soit égal à true FaireLeJob(); // On suppose que la méthode VerifierCondition renvoie du bool condition = VerifierCondition(); }

Toutes les structures de boucles de C# peuvent renoncer aux accolades encerclant le bloc de code si elles ne contiennent qu'une seule instruction.

La boucle do…while La boucle ddoo....wwhhiillee est la version "post-test" de la boucle wwhhiillee. La condition de test de la boucle est évaluée après l'exécution du corps de la boucle. En conséquence, les boucles ddoo....wwhhiillee sont utiles dans les situations dans lesquelles le corps de la boucle doit être exécuté au moins une fois. syntaxe de la boucle ddoo....wwhhiillee : do { instruction(s) } while (condition);

exemple : do { // cette boucle au moins une fois même si condition = false FaireLeJob(); // On suppose que la méthode VerifierCondition renvoie du bool condition = VerifierCondition();

67

Page 68: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

}while (condition);

La boucle foreach La boucle ffoorreeaacchh est la dernière structure de boucle disponible en C#. Cette structure de boucle a été empruntée au langage VB, et n'existait pas dans C++ ni dans Java. La boucle ffoorreeaacchh permet de procéder par itérations dans les éléments d'une collection. Pour l'instant, nous ne définirons pas en détail ce qu'est une collection (nous le verrons en détail plus loin dans ce support). Disons simplement qu'il s'agit d'un objet pouvant contenir d'autre objets dans une sorte de liste. Techniquement, pour être admis comme collection par le Framework .net, un objet doit prendre en charge une interface nommée IIEEnnuummeerraabbllee. Comme exemples de collections, citons les tableaux C#, les classes de collections définies dans les espaces de nom SSyysstteemm..CCoolllleeccttiioonnss et SSyysstteemm..CCoolllleeccttiioonnss..SSppeecciiaalliizzeedd et les classes de collection définies par les utilisateurs. Le code suivant donne un aperçu de la syntaxe de la boucle ffoorreeaacchh : // Déclaration et initialisation d'un tableau de int avec les valeurs 1,2,3,4 et 5 int[] tableauInt = {0,1,2,3,4,5}; foreach (int temp in tableauInt) { Console.WriteLine(temp); }

Ici, la boucle ffoorreeaacchh parcourt le tableau ttaabblleeaauuIInntt élément par élément. Pour chaque élément (donc à chaque itération), elle place la valeur de l'élément dans la variable tteemmpp de type iinntt et effectue une itération dans la boucle. Attention : avec la structure de boucle ffoorreeaacchh, il n'est pas possible de modifier la valeur d'un élément de la collection (représenté par la valriable tteemmpp dans cet exemple) depuis le corps de la boucle. Ainsi le code suivant est incorrect et ne peut pas être compilé : // Déclaration et initialisation d'un tableau de int avec les valeurs 1,2,3,4 et 5 int[] tableauInt = {0,1,2,3,4,5}; foreach (int temp in tableauInt) { temp++; Console.WriteLine(temp); }

Nous apprendrons plus loin dans ce cours comment utiliser et créer des objets collections sur lesquels nous pourrons itérer avec la syntaxe de boucle ffoorreeaacchh. Il est intéressant de noter que de telles classes écrites en C# peuvent également être parcourues avec la syntaxe FFoorr EEaacchh .... NNeexxtt de Visual Basic .net.

68

Page 69: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

7.3 Instruction de saut C# fournit un certain nombre d'instructions qui permettent de "sauter" immédiatement à une autre ligne de code. La première de celles-ci est bien sûr la (tristement) célèbre instruction ggoottoo.

L'instruction goto L'instruction ggoottoo permet de sauter directement à une ligne de programme spécifiée, identifiée par une étiquette. Une étiquette est un identifiant seul sur une ligne suivi d'un caractère deux-points. Syntaxe et exemple : goto Label1; Console.WriteLine("Cette ligne n'est pas exécutée"); Label1: Console.WriteLine("Cette ligne est exécutée après le goto");

Il existe certaines restrictions concernant l'instruction ggoottoo :

- Il n'est pas possible de sauter à un bloc de code tel qu'une boucle ffoorr. - Il n'est pas possible de sauter en dehors d'une classe. - Il n'est pas possible de s'échapper d'un bloc de gestion d'erreur ttrryy....ccaattcchh....ffiinnaallllyy

L'utilisatiion de ggoottoo (en général) ne se conforme pas aux règles d'une programmation objet bien structurée. Cependant, il existe des cas dans lesquels il est admis de l'utiliser (comme nous l'avons déjà vu dans l'instruction sswwiittcchh....ccaassee)

L'instruction break Nous avons déjà utilisé une instruction bbrreeaakk pour sortir d'une clause case dans une instruction sswwiittcchh. En fait, l'instruction bbrreeaakk peut également être utilisée pour sortir prématurément des boucles ffoorr, ffoorreeaacchh, wwhhiillee ou encore ddoo……wwhhiillee. Le contrôle est alors transféré juste après la fin de la boucle. Si l' instruction bbrreeaakk apparaît dans une boucle imbriquée, le contrôle est transféré à la fin de la boucle la plus interne. Si l' instruction bbrreeaakk apparaît en dehors d'une instruction sswwiittcchh ou d'une boucle, une erreur de compilation survient.

L'instruction continue L'instruction ccoonnttiinnuuee ne peut être utilisée que dans une boucle ffoorr, ffoorreeaacchh, wwhhiillee ou ddoo....wwhhiillee. Au lieu de quitter la boucle, elle fait sortir de l'itération en cours et passe à l'iteration suivante.

L'instruction return L'instruction rreettuurrnn est utilisée pour sortir d'une méthode (une fonction) et retourne le contrôle au code appelant. Si la méthode doit renvoyer une valeur, l'instruction rreettuurrnn doit être suivie d'une expression de ce type, sinon elle peut être appelée telle quelle.

69

Page 70: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3. Chapitre 3 : Structure des programmes

3.1 Les Tableaux en C#

3.1.1 Définition Un tableau est une structure indexée qui contient des objets de même type. Les tableaux peuvent posséder une ou plusieurs dimensions. Pour accéder à un élément d'un tableau, il faut spécifier une valeur d'index pour chacune des dimensions du tableau. En C#, tous les tableaux sont de base zéro. Ceci veut dire que l'index du premier élément d'un tableau sera toujours zéro, et par conséquent, l'index du dernier élément d'un tableau sera toujours égal au nombre total d'éléments dans le tableau moins un. En fait, quand nous déclarons un tableau en C#, une instance de la classe System.Array est créée en coulisses, mais les éléments du tableau sont, eux, du type avec lequel vous avez déclaré le tableau.

3.1.2 Les tableaux à une dimension Voici la syntaxe pour déclarer un tableau à une dimension : <type>[] nomtableau;

par exemple : int[] tableauInt;

Initialisation Pour initialiser un tableau de dimensions spécifiques, il nous faut utiliser le mot-clé new (ce qui confirme qu'en fait, nous instancions un objet de type System.Array) et indiquer au tableau le nombre de cases que cette dimension doit contenir : int[] tableauInt; tableauInt = new int[3] // Tableau de 3 cases. (index de 0 à 2).

on peut également (et c'est souvent assez pratique) grouper la déclaration et l'initialisation sur la même ligne : int[] tableauInt = new int[3];

On peut aussi déclarer un tableau et initialiser ses cases avec un contenu littéral en utilisant la syntaxe suivante: int[] tableauInt = new int[3] {11, 22, 33};

ou encore déclarer un tableau et initialiser ses cases sans employer l'opérateur new avec la syntaxe suivante :

70

Page 71: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

int[] tableauInt = {0, 2, 4, 6, 8, 10}

La ligne de code précédente définit un tableau de 6 cases dont les index vont de 0 à 5 et dont les valeurs sont contenues entre les accolades, séparées par des virgules. Notons également qu'il est possible de définir le nombre d'éléments pour une dimension donnée d'un tableau à l'aide d'une variable au lieu d'un littéral : int longueur; longueur = 5; string[] montableau = new string[longueur];

Accès aux éléments du tableau Pour accéder à un élément du tableau, il suffit de préciser pour chaque dimension du tableau à quel index se trouve l'élément : int[] tableauInt = {0, 2, 4, 6, 8, 10} int temp = tableauInt[2] //temp obtient la valeur 4

3.1.3 Les tableaux à plusieurs dimensions C# prend en charge les tableaux multi-dimensionnels "rectangulaires". Un tableau "rectangulaire" à plusieurs dimensions est un tableau dans lequel chaque ligne a le même nombre de colonnes. Pour déclarer un tableau à plusieurs dimensions, il nous suffit d'insérer une virgule pour séparer les dimensions dans la déclaration du tableau comme ceci : int[,] tableauRect; // Tableau à 2 dimensions int[,,] tableauCube; // Tableau à 3 dimensions

Après avoir déclaré un tableau multidimensionnel, on peut l'initialiser en spécifiant la taille de chacune des dimensions. int[,] tableauRect = new int[3,2]; // Tableau à 3x2 cases int[,] tableauCube = new int[2,2]; // Tableau à 2x2 cases

On peut aussi, comme pour les tableaux à une dimension déclarer et initialiser les valeurs contenues dans le tableau en une seule ligne. Par exemple, le code suivant déclare et initialise les valeurs de deux tableaux multidimensionnels de dimensions 2x2 et 3x2 respectivement et définit les valeurs stockées dans chacune de leurs cases int[,] tableauRect = new int[3,2] {{1,2},{3,4},{5,6}}; string[,] noms = new string[2,2] {{"aa","bb"},{"cc","dd"}};

Il possible de ne pas spécifier explicitement la taille des tableaux, auquel cas leur taille dépendra du nombre d'élements littéraux qui leur seront alloués. Voici les mêmes tableaux que précédemment : int[,] tableauRect = new int[,] {{1,2},{3,4},{5,6}}; string[,] noms = new string[2,2] {{"aa","bb"},{"cc","dd"}};

71

Page 72: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

// ou encore.. int[,] tableauRect = {{1,2},{3,4},{5,6}}; string[,] noms = {{"aa","bb"},{"cc","dd"}};

3.1.4 Les tableaux orthogonaux (jagged arrays) Le second type de tableau multi-dimensionnel que C# prend en charge est le tableau orthogonal ou "jagged array", ou encore tableau de tableaux. Dans un tableau orthogonal, chaque case contient un tableau, ce qui fait que l'on peut avoir des structures non-rectangulaires. Pour déclarer des tableaux de tableaux, on utilise des jeux de crochets avec la syntaxe suivante :

Déclaration int[][] jaggedArray;

Initialisation Malheureusement, l'initialisation de ces tableaux n'est pas aussi simple que celle des tableaux rectangulaires à plusieurs dimensions. Pour les initialiser, nous avons deux solutions: La première solution consiste à initialiser d'abord le tableau contenant les sous-tableaux, puis les les sous-tableaux proprement dits : int[][] jaggedArray; jaggedArray = new int[2][]; // init du tableau contenant jaggedArray[0] = new int[3]; // init du sous tableau jaggedArray[1] = new int[4]; // init du sous tableau

La deuxième solution consiste à utiliser une forme modifié de l'affectation littérale, comme suit : int[][] jaggedArray; jaggedArray = {new int[]{0,1,2), new int[]{0,1,2,3}}

72

Page 73: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Parcours des tableaux de tableaux Pour accéder aux données des tableaux de tableaux, l'imbrication de boucles for est plus courante que l'usage de boucle foreach. Par exemple, le tableau suivant contient 10 tableaux, qui, à leur tour, contiennent un tableau d'entiers qui sont diviseurs d'un entier entre 1 et 10. int[][] diviseurs1a5 = {new int[] {1}, new int[] {1, 2}, new int[] {1, 3}, new int[] {1, 2, 4}, new int[] {1, 5}, new int[] {1, 2, 3, 6}, new int[] {1, 7}, new int[] {1, 2, 4, 8}, new int[] {1, 3, 9}, new int[] {1, 2, 5, 10}};

si l'on souhaite itérer et imprimer les valeurs du tableau, il faut utiliser soit : Console.WriteLine("Impression des valeurs avec boucle for :\n\n"); for(int x = 0 ; x < diviseurs1a10.Length ; x++) { for(int y = 0 ; y < diviseurs1a10[x].Length ; y++) { Console.Write("[{0}] ",diviseurs1a10[x][y]); Console.Write("\0"); } Console.WriteLine(""); }

soit : Console.WriteLine("Impression des valeurs avec boucle foreach :\n\n"); foreach (int[] diviseursEntiers in diviseurs1a10) { foreach (int diviseur in diviseursEntiers) { Console.Write("[{0}] ",diviseur); } Console.WriteLine(); } }

73

Page 74: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.1.5 La classe Array et ses méthodes. La classe System.Array est la classe de base pour tous les tableaux en C#. Cette classe fournit des méthodes pour manipuler, créer, trier et rechercher des éléments dans les tableaux.

Propriétés de System.Array Class IsFixedSize Indique si le tableau a une taille fixe ou pas. IsReadOnly Indique si le tableau est en lecture seule. Length le nombre total d'éléments du tableau, toutes dimensions confondues Rank le nombre de dimensions du tableau.

Méthodes de System.Array Class. BinarySearch Cette méthode recherche un élément dans un tableau à une dimension en

utilisant un algorithme de recherche binaire. Clear Supprime tous les éléments du tableau. Copy Cette méthode copie une partie d'un tableau dans un autre tableau. CopyTo Cette méthode copie tous les éléments du tableau à une dimension en

cours dans un autre tableau, en démarrant à l'élément d'index spécifié dans le tableau destination

GetEnumerator Renvoie un objet IEnumerator pour le tableau GetLength Renvoie le nombre d'éléments dans le tableau. GetLowerBound Renvoie l'index de base pour la dimension spécifiée. GetUpperBound Renvoie l'index supérieur pour la dimension spécifiée. IndexOf Renvoie l'index de la première occurrence d'une valeur recherchée dans un

tableau ou une portion de tableau. LastIndexOf Renvoie l'index de la dernière occurrence d'une valeur recherchée dans un

tableau ou une portion de tableau. Reverse Inverse l'ordre des éléments dans un tableau à une dimension. Sort Trie le tableau (uniquement pour les types intrinsèques ou les types qui

implémente Icomparable).

74

Page 75: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.2. Les Enumérations

3.2.1 Définition et usage Une énumération est un en fait un jeu de constantes numériques fortement typées. Il existe de nombreux cas dans lesquels une fonction ou une variable doivent recevoir une valeur comprise dans un jeu déterminé de valeurs. Une énumération est un type valeur. Les enumérations remplissent ce rôle. Le Framework .net définit un grand nombre d'énumérations et nous pouvons bien sûr définir nos propres énumérations. Le mot-clé enum permet de définir une énumération avec la syntaxe suivante :

eennuumm <<nnoommEEnnuumm>> {{ vvaalleeuurr11,, vvaalleeuurr22,,

vvaalleeuurrXX }}

Une fois une énumération définie, on peut déclarer des variable du type de cette énumération avec la syntaxe suivante :

<nomEnum> nomVar; Les valeurs doivent être attribuées aux variables de type énumérés avec la syntaxe suivante : nomVar = nomEnum.Valeur; Il est intéressant de noter le support IntelliSense de l'éditeur de Visual Studio, qui nous permet lors de l'affectation d'une valeur à une variable de type énumération, de voir apparaître toutes les valeurs définies dans l'énumération. Ceci évite bien des fautes et permet aux développeurs de ne pas avoir à se souvenir des plages de valeurs acceptées par la variable ou l'élement de type énumération.

3.2.2 Typage sous-jacent des énumérations Les énumérations possèdent un type sous-jacent nécessaire au stockage des données. Chaque valeur admise par le type énumération est stockée en tant que valeur de ce type (int par défaut). Il est possible de changer le type sous-jacent par défaut pour les énumérations avec la syntaxe suivante :

eennuumm <<nnoommEEnnuumm>> :: <<ttyyppeeSSoouussJJaacceenntt>> {{ vvaalleeuurr11,, vvaalleeuurr22,,

vvaalleeuurrXX }}

Les types sous-jacent autorisés pour les énumérations sont : byte, sbyte, short, ushort, int, uint, long et ulong. Par défaut, chaque valeur reçoit automatiquement une valeur du type sous-jacent, en partant de zéro et en augmentant de 1 à chaque nouvelle valeur. Il est cependant possible de définir explicitement les valeurs pour une ou plusieurs des constantes définies dans le corps de l'énumération avec la syntaxe suivante :

75

Page 76: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

eennuumm <<nnoommEEnnuumm>> :: <<ttyyppeeSSoouussJJaacceenntt>> {{ vvaalleeuurr11 == vvaalleeuurr11,, vvaalleeuurr22 == vvaalleeuurr22,,

vvaalleeuurrXX == vvaalleeuurr33 }}

3.2.3 Méthodes de la classe Enum La classe System.Enum définit des méthodes statiques pratiques pour effectuer différentes opérations sur les types énumérations. Citons entre autres les méthodes GetName(), GetNames, Parse(), et GetValues().

3.3 Les espaces de noms (namespaces) Les espaces de nom (ou namespaces) nous fournissent un moyen efficace de regrouper des éléments (classes, structs, énumérations, etc..) dans des structures sémantiques. Contrairement à un fichier ou à un composant, un namespace ne reflète pas un emplacement physique mais plutôt une appartenance logique.

3.3.1 importance des espaces de nom Quand nous définissons une classe par exemple, nous pouvons (et devons) l'inclure dans un namespace. Par la suite, si nous créons une autre classe dont le but est apparenté à celui de la première, nous l'incluerons dans le même namespace, créant ainsi un "groupement" indiquant aux développeurs utilisant ces classes qu'elles sont apparentées. Voici par comment inclure une classe dans un namespace namespace MonApplication { using System; public class Client

{ // du code ici.. }

}

Dans cet exemple, la classe Client est inscrite dans le namespace MonApplication. Le placement d'un type dans un namespace confère à ce type un nom dit "qualifié" composé du nom du (ou des) namespace(s) contenant le type séparés par des points, plus le nom du type lui-même. Ici, le vrai nom de la classe Client est MonApplication.Client. Cette classification nous permet d'éviter toute collision entre (par exemple) deux classes qui posséderaient le même nom. Si celle-ci se trouvent dans deux namespaces différents, il suffira de les appeler par leurs nom qualifiés pour les différencier. Il est également possible d'imbriquer des namespaces pour segmenter logiquement une application, créant ainsi une structure sémantique hiérarchisée : namespace MaSociete

76

Page 77: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

{ namespace MonApplication { namespace LogiqueMetier { class Client { // code de Client.. } } } }

Ici, le nom complet (ou "qualifié") de la classe Client est :

MMaaSSoocciieettee..MMoonnAApppplliiccaattiioonn..LLooggiiqquueeMMeettiieerr..CClliieenntt

Nous aurions également pû définir directement la hiérarchie des namespaces comme suit pour obtenir exactement le même résultat : namespace MaSociete.MonApplication.LogiqueMetier { class Client { // code de Client.. } }

NOTE : Il n'est cependant pas possible de déclarer un namespace multipart imbriqué dans un autre namespace.

3.3.2 Conventions pour namespaces et répertoires Il est d'usage de calquer autant que possible la structure des répertoires dans lesquels on stocke les différents projets et solutions sur la structure hiérarchique des namespaces. On essaiera également si l'on utilise Visual SourceSafe pour gérer notre code source, de définir dans ce logiciel une structure de projets de même structure que les namespaces que nous utilisons. Ainsi, il est beaucoup plus simple de repérer rapidement les structures logiques composant nos applications.

77

Page 78: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.3.3 Instruction using L'instruction using, que nous avons déjà remarquée dans tous les exemples de code que nous avons abordés, sert à importer les espaces de noms dans notre code, nous évitant ainsi de devoir entrer les noms qualifiés pour chacun des objets que nous utilisons. Cette instruction a la syntaxe suivante : using nomNamespace;

Nous avons remarqué par exemple que tous nos fichiers de code importaient le namespace System. La raison pour cela est que tous les types intrinsèques et les objets très communs se trouvent dans ce namespace. On pourrait se passer de l'instruction using System, mais il faudrait alors saisir les noms qualifiés pour chacune des variables que nous définissons appartenant au namespace System, ce qui serait fastidieux.

3.3.4 Liste des principaux namespaces Voici la liste des principaux namespaces du framework.net : NameSpace Contenu SSyysstteemm ttoouuss lleess oobbjjeettss iinnttrriinnssèèqquueess SSyysstteemm..IIOO eennttrrééeess // ssoorrttiieess eett ffiicchhiieerrss SSyysstteemm..XXMMLL XXMMLL SSyysstteemm..CCoolllleeccttiioonnss oobbjjeettss CCoolllleeccttiioonnss,, LLiisstteess eett

ssttrruuccttuurreess ddee ddoonnnnééeess SSyysstteemm..DDaattaa AAccccèèss aauuxx ddoonnnnééeess SSyysstteemm..DDiiaaggnnoossttiiccss AAccccèèss aauuxx llooggss,, ttrraaccee,, eettcc.... SSyysstteemm..DDrraawwiinngg GGDDII++ eett ggrraapphhiissmmeess SSyysstteemm..WWiinnddoowwss..FFoorrmmss IInntteerrffaaccee WWiinnddoowwss SSyysstteemm..RReefflleeccttiioonn RRééfflleexxiioonn eett mmééttaaddoonnnnééeess.. SSyysstteemm..SSeeccuurriittyy SSééccuurriittéé SSyysstteemm..TTeexxtt..RReegguullaarrEExxpprreessssiioonnss RReeggEExxpp SSyysstteemm..TTeexxtt FFoonnccttiioonnss TTeexxttee SSyysstteemm..WWeebb..UUII IInntteerrffaacceess WWeebb SSyysstteemm..WWeebb AAccccèèss WWeebb Il existe bien sûr bien d'autres namespaces et sous-namespaces. La liste complète de ceux-ci avec leurs descriptions est disponible dans la documentation MSDN de Visual Studio à l'URL : ms-help://MS.VSCC.2003/MS.MSDNQTR.2003FEB.1033/cpref/html/cpref_start.htm

78

Page 79: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.4 Classes et Structures Les classes et les structures sont différentes en cela que (entre autres) les structures sont des types valeurs et les classes des types références.

3.4.2 Définir des classes et des structures

Structures Une structure est un élément de type valeur (qui dérive donc directement de System.ValueType) et qui stocke ses valeurs sur la pile. Les structures se comportent donc toujours comme des types valeurs. Les structures sont en général utilisées pour représenter des éléments "légers" comme par exemple un Point, un Rectangle ou encore une Couleur (ou tout autre type de données contenant peu d'informations). Voici la syntaxe pour déclarer une structure : struct Point2D { membres de la structure. int x; int y; }

Une structure peut:

- contenir un ou plusieurs constructeurs prenant des paramètres. - contenir des variables membres. - contenir des propriétés. - contenir des redéfinitions d'opérateurs. - contenir des méthodes.

Une structure ne peut pas :

- hériter d'une autre structure - initialiser ses variables membres lors de leur déclaration - contenir un constructeur sans paramètre - posséder de destructeurs

C'est une erreur que de déclarer un constructeur sans paramètres pour une struct. Un constructeur par défaut est toujours implicitement fourni, qui initialise tous les membres de la structure à leur valeur par défaut. C'est une erreur que d'initialiser des champs d'une structure directement lors de leur déclaration. Bien que les structs soient des types valeurs, il est possible de les déclarer comme des classes : Point2D myPoint; ou encore : Point2D myPoint = new Point2D();

La différence entre les deux types de déclarations suivantes est la suivante :

- lorsque l'on déclare une variable de type struct sans le mot-clé new, ses variables-membres ne sont pas initialisées et il faudra alors les initialiser avant de pouvoir s'en servir.

79

Page 80: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

- lorsque l'on déclare une variable de type struct avec le mot-clé new, les variables membre de la struct sont automatiquement initialisées à leurs valeurs par défaut.

Classes Les classes sont des types valeurs (héritant donc directement de System.Object) et se définissent en utilisant la syntaxe suivante : <modificateurs d'accès> class NomClasse { // membres de la classe. }

Une classe est en fait un prototype qui va définir la "forme" et le comportement des objets qui vont être de ce type. Le mot <modificateurs d'accès> sera étudié plus en détail lorsque nous parlerons de l'héritage, mais on peut déjà dire que les modificateurs d'accès spécifient les différents possibilités d'instanciation des classes (comme public ou private par exemple) les classes peuvent :

- contenir un ou plusieurs constructeurs prenant des paramètres ou pas. - contenir des variables membres. - contenir des propriétés. - contenir des indexeurs - contenir des redéfinitions d'opérateurs. - contenir des méthodes. - hériter d'une autre classe - posséder des destructeurs

3.4.3 Différence entre une classe et un objet. Une classe est en fait le modèle conceptuel qui va définir le comportement des objets issus de cette classe. Un objet est un élément qui possèdera toutes les caractéristiques de la classe dont il est une instance. Pour prendre un parallèle, on pourrait considérer la classe comme un moule à gateaux et les objets comme les gateaux résultant de la cuisson dans ce moule.

80

Page 81: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.5 Méthodes dans C#

3.5.1 Déclaration de méthodes Définition (ECMA) Une méthode est un membre d'une classe qui implémente des opérations qui peuvent être exécutées par un objet ou une classe. Les méthodes ont une liste (possiblement vide) de paramètres, une valeur de retour (à moins que la valeur de retour soit void) et sont dites soit statiques soit non-statiques. Les méthodes non statiques, également appelées méthodes d'instances, sont appelées par des instances de la classes les contenant, alors que les méthodes statiques sont appelées par la classe elle-même. Les méthodes statiques doivent faire figurer le mot-clé static dans leur déclaration.

3.5.2 valeurs de retour Une méthode peut avoir une valeur de retour, auquel cas elle doit le signaler dans sa signature avec la syntaxe : <typeValeurRetour> NomMéthode ( ...) et doit indiquer la valeur renvoyée avec la syntaxe : return valeur; Par exemple une méthode statique renvoyant un int et nommée GetCount() doit s'écrire : static int GetCount() { .. code return <valeur int>; }

Les méthodes qui ne renvoient doivent être déclarées avec le mot-clé void doivent comprendre une instruction return non suivie d'une valeur : Par exemple une méthode statique ne renvoyant rien nommée DoTheJob() doit s'écrire : static void DoTheJob() { .. code return; }

3.5.3 Invocation de méthodes

3.5.4 La méthode Main et ses différentes syntaxes La méthode Main est la méthode qui est exécutée en premier lors de l'exécution d'un programme. Cette méthode est toujours statique et doit avoir comme type de retour soit int soit void. Voici les différents prototypes possibles pour la méthode Main :

81

Page 82: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

ssttaattiicc vvooiidd MMaaiinn(()) ssttaattiicc vvooiidd MMaaiinn((ssttrriinngg[[]] aarrggss)) ssttaattiicc iinntt MMaaiinn(()) ssttaattiicc iinntt MMaaiinn((ssttrriinngg[[]] aarrggss)) Bien qu'il soit fréquent de spécifier explicitement le modificateur public, ceci n'est pas nécessaire et est le niveau d'accès par défaut affecté à la méthode Main. En fait, le programme fonctionnera même si Main est marqué comme private.

3.5.5 Passage d'arguments à Main Jusqu'à maintenant, dans les exemples de code étudiés, la méthode Main ne comportait jamais de paramètres. Toutefois, lorsqu'un programme est lancé, le CLR peut passer à la méthode Main tous les arguments définis sur la ligne de commande DOS (on peut également les définir dans Visual Studio). Pour que la méthode Main puisse traiter ces arguments, il faut qu'elle ait l'une des signatures suivantes : ssttaattiicc vvooiidd MMaaiinn((ssttrriinngg[[]] aarrggss)) ssttaattiicc iinntt MMaaiinn((ssttrriinngg[[]] aarrggss)) Dans ce cas, la méthode Main peut recevoir des arguments passés soit par la ligne de commande directement, soit spécifiées dans la boite de dialogue "Propriétés du Projet | Propriétés de configuration|Deboguage|Arguments de la ligne de commande. A noter que le premier des arguments est toujours le nom de l'exécutable lui-même.

82

Page 83: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.5.6 Passage d'arguments par valeur et par référence

Mot-clé ref On peut passer les arguments par valeur ou par référence. Le mode de passage des arguments est par valeur par défaut. Si l'on souhaite passer un argument par référence à une fonction, on doit spécifier le mot-clé ref pour cet argument dans le prototype de la fonction mais également lors de l'appel de cette fonction comme démontré dans le code suivant : static void ModifyValue(ref int val) { val += 1; } // Appel du code .. static void Main() { int test = 10; ModifyValue(ref test); // Après appel de ModifyValue, test vaudra 11. }

Le passage d'arguments par référence permet aux fonctions appelée de modifier des valeurs dans les fonctions appelantes. On note qu'une variable doit être explicitement initialisée avant de pouvoir être passée en tant que paramètre ref à une procédure.

Mot-clé Out Le langage C# dispose également du mot-clé out qui induit le même comportement que le mot-clé ref, à la différence que la variable passée à la procédure n'a pas besoin d'être initialisée avant d'être transmise à la procédure appelante.

3.5.7 Passage de tableaux aux méthodes C# permet le passage de tableaux aux méthodes de la manière suivante : static void ModifyArray(int[] tableau) { for (int i = 0; i <= tableau.Length; i++) tableau[i] = i; }

83

Page 84: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Mot-clé Params le mot-clé params permet le passage d'un nombre d'arguments variable à une fonction : static void ModifyValues(params int[] tableau) {

for (int i = 0; i <= tableau.Length; i++) tableau[i] = i; }

Dans ce cas, le code appelant n'a pas besoin de fournir un tableau à proprement parler et la fonction ci-dessus peut être appelée avec la syntaxe suivante : int i, j, k; i = j = k = 10; ModifyValues(i,j,k);

Le paramêtre tableau de la fonction ModifyValues contiendra alors : tableau[0] // sera égal à i tableau[1] // sera égal à j tableau[2] // sera égal à k

3.5.8 Surcharger des méthodes. Le mécanisme appelé surcharge de méthodes permet de spécifier, dans une même classe ou structure, plusieurs méthodes portant le même nom, mais n'ayant pas la même signature. par exemple : static long addition(int val1, int val2) { return (val1 + val2); } static int addition(byte val1, byte val2) { return (val1 + val2); }

Ces deux méthodes ont bien le même nom mais ni le même type de retour, ni les mêmes types de paramètres. Note : On ne peut pas définir de surcharge si :

- deux méthodes diffèrent uniquement par leur type de retour. - deux méthodes diffèrent uniquement par un paramètre ref ou out. - deux méthodes diffèrent uniquement par les noms de leurs paramètres.

84

Page 85: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.5.9 Membres statiques et Membres d'instance Il faut différencier les méthodes dites statiques et les méthodes dites d'instance. Les méthodes statiques doivent être déclarées avec le mot clé static et sont accessibles sans qu'il soit besoin de créér une instance de la classe qui les contient. Les membres statiques (ou partagés) sont partagés entre toute les instances d'une même classe, ce qui permet d'économiser de la mémoire. Pour appeler un membre statique d'une classe, il faut utiliser la syntaxe : NomClasse.NomMembreStatique

et nom pas NomObjet.NomMembre car les membres statiques s'appliquent aux classes et non aux objets. Par exemple, les instructions Console.WriteLine() ou convert.ToString()sont statiques et on n'a pas besoin de créer une instance de la classe Console pour appeler la méthode WriteLine(), on peut l'appeler directement avec le nom de la classe Console (par ailleurs, dans le cas de la classe Console, on ne peut appeler que ses membres statiques car il est impossible de créér une instance de cette classe) Note: Par exemple, la méthode Main d'une application de type "Application Console" est toujours statique ! En effet, si cette méthode n'était pas statique, il faudrait créér une instance de la classe contenant Main, mais cela supposerait que du code créée une instance avant de pouvoir appeler Main.

85

Page 86: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.6 Propriétés Une propriété est un type de membre de classe particulier permettant en général l'accès à une variable membre de la classe de manière protégée.

3.6.1 Concept d'encapsulation Le concept d'encapsulation est l'un des grands concepts de la programmation orientée objet. On encapsule une variable dans une propriété, de manière à avoir tout contrôle sur les opérations faites sur cette variable par un client de la classe dans laquelle cette propriété est définie. Supposons le cas suivant : Nous voulons définir une classe Employé présentant un membre "Age" qui représentera l'âge du salarié. Nous pourrions tout-à fait définir la classe comme ceci : public class Salarié { public byte Age; }

avec le code ci-dessus, un client disposant d'un objet Salarie pourrait tout à fait intervenir sur le membre Age en lecture et en écriture avec par exemple avec le code suivant : Salarié UnSalarié = new Salarié(); UnSalarié.Age = 500; Console.WriteLine(UnSalarié.Age);

Cependant, si nous voulions restreindre la plage des âges possibles pour un objet Salarié à la tranche 18-65 ans, nous ne pourrions le faire, car la variable Age est publique. Nous pourrions alors décider de passer cette variable en private, mais il nous faudrait alors écrire une méthode permettant de lire la valeur de l'âge d'un salarié et une autre permettant de définir la valeur de l'âge de ce même salarié. Ce procédé s'appelle "encapsuler" une variable. Ce cas de figure étant très courant, et afin de limiter le nombre de procédures, le langage C# permet l'écriture de propriétés.

86

Page 87: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.6.2 Syntaxe des propriétés Une propriété est un type de membre particulier qui permet l'accès en lecture et/ou écriture à des variables encapsulées dans une classe. Voici la syntaxe que nous pourrions utiliser pour modifier la classe Salarié : public class Salarié { private byte _Age; public byte Age

{ get {return _Age; } set {_Age = value; } }

}

Dans ce code, on constate que la variable _Age est maintenant private et que l'on ne peut donc y accéder depuis l'extérieur de la classe. On fournit donc à cet effet une propriété Age permettant l'accès en lecture et écriture à cette variable. Lorsqu'un client voudra lire la valeur de la propriété Age, l'accesseur get de la propriété sera appelé, et l'accesseur set sera appelé quand un client voudra écrire la valeur de la propriété. Avec cette syntaxe, on constate que nous avons bien encapsulé l'accès à la variable _Age et que nous avons donc toute lattitude pour effectuer des traitements supplémentaires lors de l'accès à cette propriété. Par exemple, si, comme nous l'avions évoqué dans le paragraphe précédent, nous voulions limiter la plage des valeurs possibles pour la propriété Age à la tranche 18-65 ans, il nous suffirait d'ajouter du code de vérification à l'accesseur set de la propriété, comme ceci : public class Salarié { private byte _Age; public byte Age

{ get {return _Age; } set { if (_Age < 18 || _Age > 65) Console.Write("Âge non correct"); else _Age = value; }

} }

87

Page 88: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.6.3 Considérations générales

Lecture / écriture Si l'on souhaitait limiter l'accès à la propriété en lecture seule, il suffirait de ne pas fournir l'accesseur set, et inversement, si l'on voulait une propriété en écriture seule, il suffirait de ne pas écrire l'accesseur get.

Accès différents Il n'est pas possible de spécifier différents accès pour les accesseurs get et set d'une même propriété.

3.6.4 Indexeurs Un indexeur est un type spécifique de propriété permettant l'accès à un membre de classe avec la même syntaxe qu'un tableau. Les indexeurs sont très utilisés en C# dans le Framework et nous pouvons également définir un ou plusieurs indexeurs pour nos classes. Imaginons le cas suivant : public class TableauDeChaines {

private string[] _tableau = {"AA","BB","CC","DD","EE"}; public string this[byte index] { get { return _tableau[index]; } set { _tableau[index] = value; } } }

Ici, nous avons défini un indexeur. Un indexeur est une propriété avec la syntaxe suivante : <<mmooddiiffiiccaatteeuurrAAccccèèss>> <<TTyyppeeRReettoouurr>> tthhiiss[[<<TTyyppeePPaarraammèèttrree>> <<NNoommPPaarraammèèttrree>>]] On note que le nom d'un indexeur est toujours this et que cette propriété s'appelle dans le code client de la façon suivante : TableauDeChaines monTableau = new TableauDeChaines(); monTableau[0] = "ZZ"; // Stocke "ZZ" dans _tableau Console.WriteLine(monTableau[0]); // Lit "ZZ" dans _tableau.

On peut définir plusieurs indexeurs dans une même classe du moment que ceux-ci respectent les règles définies pour surcharger des méthodes (voir point 3.5.8). Par exemple, on pourrait avoir l'indexeur :

- public string this[byte index] qui nous permettrait de lire ou d'écrire à la position spécifiée par index dans le tableau contenu dans la classe.

- public int this[string val] qui nous permettrait d'obtenir l'index de la case contenant la valeur spécifiée

par le paramêtre val de l'indexeur.

88

Page 89: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.7 Delegates et Evènements

3.7.1 Définition d'un Delegate Définition : Un delegate est un type permettant de stocker des références à des fonctions. Les delegates sont déclarés comme des fonctions vides, à l'aide du mot-clé delegate. La déclaration d'un delegate est une signature de fonction comportant un type de retour et une liste de paramètres. Une fois défini, un delegate peut être utilisé comme type d'une variable, celle-ci pouvant alors être initialisée comme référence à une fonction ayant la même signature que le delegate. La fonction peut alors être appelée à l'aide de la variable delegate comme s'il s'agissait d'une fonction. Voici la syntaxe de déclaration d'un delegate : <accès> delegate <typeRetour> NomDelegate(<paramètres>);

par exemple : public delegate int processDelegate(int param1, int param2);

3.7.2 Exemple d'utilisation d'un delegate simple Une fois un delegate défini, on peut l'utiliser pour appeler dynamiquement des fonctions comme dans l'exemple suivant : public class TestDelegate { delegate double processDelegate(int p1, int p2); static double Multiplier(int p1, int p2)

{ return p1 * p2; }

static double Diviser(int p1, int p2)

{ return p1 * p2; }

static void Main() { int i = 10; int j = 15; processDelegate process; Console.WriteLine("M pour Multiplier, D pour diviser"); string input = Console.ReadLine().ToUpper(); if (input == "M") process = new ProcessDelegate(Multiplier); else process = new ProcessDelegate(Diviser);

89

Page 90: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Console.WriteLine("Résultat :{0}",process(i,j);

} }

Ce code définit un delegate dont la signature est la même que les deux fonctions Diviser et Multiplier. La fonction Main déclare ensuite une variable process du type de ce delegate. Puis, selon la réponse de l'utilisateur, on affecte à process une nouvelle instance du delegate processDelegate qui pointe soit sur la fonction Multiplier soit sur la fonction Diviser. Enfin, on appelle la fonction représentée par le delegate avec la syntaxe : process(i,j);

3.7.2 Delegates Multicast Dans l'exemple précédent, le delegate que nous avons utilise n'enveloppait qu'un seul appel de méthode. L'appel d'un delegate revient donc à appeler cette méthode. Si nous voulions appeler plusieurs fois la méthode, il nous faudrait effectuer plusieurs fois un appel explicite par l'intermédiaire du delegate. Cependant, il est possible qu'un delegate enveloppe plusieurs appels de méthodes. Un tel delegate est appelé "delegate multicast". Pour que cela ait un sens il faut que le type delegate retourne void (sinon, où iraient les valeurs de retour ?). En fait, dès que le compilateur voit un delegate qui renvoie void, il suppose qu'il s'agit d'un delegate multicast. Prenons un exemple : delegate void MyDelegate(string s); class TestMultiCastDelegate { static void Hello(string s) { Console.WriteLine("Hello {0}",s); } static void GoodBye(string s) { Console.WriteLine("Goodbye {0}",s); } static void Main()

{ MyDelegate a,b,c,d; a = new MyDelegate(Hello); b = new MyDelegate(GoodBye); c = a + b; d = c – a; a("A"); b("B"); c("C"); d("D"); }

}

Le code précédent génère la sortie suivante : Hello A // appel de a("A"); GoodBye B // appel de b("B"); Hello C // appel de c("C");

90

Page 91: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

GoodBye C // appel de c("C"); GoodBye D // appel de d("D");

On peut donc "composer" un delegate multicast de façon à ce qu'il appelle plusieurs fonctions à la suite en utilisant l'opérateur "+". On peut supprimer un delegate d'un delegate multicast en utilisant l'opérateur "-". Quand on appelle un delegate multicast, il appelle dans l'ordre tous les delegates avec lesquels il a été composé.

3.7.1 Evènements Un évènement est une notification (un message) qu'un objet envoie à un autre objet. Vous avez certainement déjà utilisé des évènements si vous avez, par exemple exécuté du code lorsqu'un utilisateur cliquait sur un bouton de votre feuille. Un évènement doit appeler des "gestionnaires d'évènements" qui sont la ou les fonctions qui seront appelées lorsque l'évènement sera déclenché. Nous allons prendre un exemple de code pour étudier le fonctionnement des évènements. Pour cela, nous allons définir une classe Generateur avec une propriété Text. Quand la valeur de cette propriété Text va changer, nous déclencherons un évènement nommé Changed. Puis, nous allons définir une classe Client qui contiendra une propriété de type Generateur nommée MyGenerateur. Lorsque nous changerons la propriété Text de cette propriété MyGenerateur, nous traiterons l'évènement Changed en affichant dans la console un message indiquant que le texte a changé. Les évènements font appel aux delegates pour fonctionner. On peut décomposer le processus pour générer et traiter un évènement en quatre étapes principales :

- déclarer le delegate qui va définir la signature des gestionnaires d'évènements - déclarer l'évènement lui-même dans la classe Generateur - déclencher l'évènement lors de l'accès en écriture à la propriété Text. - souscrire à l'évènement dans la classe Client.

91

Page 92: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Etape 1: Déclarer le delegate. Pour pouvoir déclarer un évènement, il faut d'abord déclarer un type delegate, dont le prototype définit le jeu d'arguments qui vont être passés à la méthode qui va traiter l'évènement dans la classe Client (dans laquelle se trouveront les gestionnaires d'évènement). public delegate void TextChangedEventHandler();

La signature du delegate TextChangedEventHandler définit la signature des fonctions qui vont traiter l'évènement dans la classe Client.

Etape 2: Définir la classe Generateur Voici maintenant le code de la classe Generateur : public class Generateur { // déclaration de l'évènement. public event TextChangedEventHandler Changed; private string _Text = ""; public string Text { get {return _Text;} set { _Text = value; if(Changed != null) Changed(); } } }

Déclarer l'évènement : Voici la syntaxe utilisée pour déclarer un évènement : ppuubblliicc eevveenntt <<TTyyppeeDDeelleeggaattee>> <<NNoommEEvveenneemmeenntt>>;; Ici, on déclare l'évènement Changed qui est du type Delegate TextChangedEventHandler. Déclencher l'évènement : Dans l'accesseur set de la propriété Text, on va d'abord vérifier si des clients se sont bien abonnés à l'évènement. Si c'est le cas, le delegate Changed sera différent de null (car il pointera sur la fonction destinée à traiter l'évènement). On vérifie donc si des clients ont souscrit à l'évènement avant de le déclencher (en effet si aucun code n'est "branché" pour traiter l'évènement, ce n'est pas la peine de le déclencher !) C'est tout ce dont nous avons besoin pour déclencher l'évènement dans la classe Generateur !

92

Page 93: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Etape 3: Définir la classe Client Voici le code de la classe Client : public class Client { private Generateur _gen; // Constructeur de la classe Client public Client() { _gen = new Generateur(); // on souscrit à l'évènement Changed.. _gen.Changed += new TextChangedEventHandler(CatchEvent); } // définition de la propriété MyText. public Generateur MyText { get {return _gen; } } // méthode traitant l'évènement Changed. private void CatchEvent() { Console.WriteLine("L'évènement Changed s'est produit"); } }

Ici, on déclare une variable privée de type Generateur, que l'on instancie dans le constructeur de la classe.

Etape 4: Souscrire à l'évènement et le traiter Pour souscrire à l'évènement Changed, il faut indiquer quelle fonction on souhaite voir exécutée lorsque l'évènement se déclenchera. Pour cela, il faut composer un nouveau delegate pointant sur la méthode qui va traiter l'évènement (cette méthode doit bien sûr avoir la même signature que celle du delegate de l'évènement) : _gen.Changed += new TextChangedEventHandler(CatchEvent);

Cette ligne de code indique que lorsque l'évènement Changed va se déclencher, on va exécuter la méthode CatchEvent qui possède la même signature que le delegate TextChangedEventHandler. Depuis l'extérieur de la classe dans laquelle il est déclaré, un évènement ressemble à un champ, mais l'accès à ce champ est très limité. Les seules choses que l'on puisse faire sont soit s'abonner à l'évènement (en composant un nouveau delegate), soit se désabonner de l'évènement. Ces deux opérations sont faites avec les opérateurs += et -=.

93

Page 94: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4. Chapitre 4 : Déboguage et gestion d’erreurs

1. Introduction Nous avons jusqu’à présent étudié les concepts élémentaires de la programmation C#. Avant d’aborder la programmation orientée objet dans une prochaine partie, nous allons nous pencher sur le débogage et la gestion d’erreurs. Les erreurs de codage sont inévitables et indépendantes des compétences du développeur. La capacité de les anticiper fait d’ailleurs parties des qualités d’un bon développeur. Ces erreurs désignent à la fois les erreurs syntaxiques qui empêchent la compilation (on les appelle des erreurs de syntaxe), mais peuvent également survenir pendant l’exécution du programme. D’autres erreurs sont plus subtiles. Votre application ne parvient peut-être pas à ajouter un enregistrement dans une base de données car vous avez oublié d’indiquer un champs nécessaire ou ajouté un enregistrement erroné dans d’autres circonstances bien précises. De telles erreurs, qui impliquent la logique applicative, sont appelées erreurs sémantiques ou erreurs de logique. Le plus souvent, les erreurs les plus subtiles sont signalées par les utilisateurs qui se plaignent que quelque chose ne fonctionne pas correctement. Dans de telles situations, vous pourrez constater que les fonctions de débogage de VS sont vraiment d’un grand secours. Dans cette première partie, nous aborderons les techniques mises à votre disposition pour régler des problèmes récurrents. En outre, nous étudierons les techniques de gestion d’erreurs disponibles en C#. Ces techniques sont propres au langage C#, mais VS offre également des outils de débogage performants.

2. Déboguage dans Visual Studio .net Le mode débogage est un mode d’exécution spécifique pour les applications. Les versions de débogage enregistrent des informations symboliques sur l’application, de telles façons que Visual Studio .net puisse savoir exactement ce qui se passe ligne après ligne. Les informations symboliques conservent, entre autres, les noms des variables utilisées dans le code non compilé, ce qui permet d’établir une correspondance avec ces dernières et les valeurs existantes dans l’application compilée en code machine, qui comporte des informations incompréhensibles pour le développeur. Ces informations sont stockées dans des fichiers à l’extension .pdb qui résident dans les répertoires Debug. Elles peuvent être exploitées pour effectuer, entre autres, les opérations utiles suivantes :

• Affichage d’informations de débogage dans VS ; • Examen et modification des valeurs de variables lors de l’exécution de l’application ; • Suspension et reprise de l’exécution du programme ; • Arrêt automatique du programme à certains emplacements du code ; • Exécution pas à pas du programme ; • Contrôle des modifications du contenu d’une variable pendant l’exécution de l’application ; • Modification du contenu des variables à l’exécution ; • Exécution d’appels de test de fonctions ;

Dans cette partie, nous étudierons ces techniques et la façon de les utiliser pour identifier les zones de code qui ne fonctionnent pas comme prévu et les corriger, activités connues sous le nom de débogage.

94

Page 95: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Selon la terminologie VS, une application s’exécute en mode normal ou en mode point d’arrêt ; dans ce dernier cas, l’exécution normale de l’application est interrompue. Nous étudierons tout d’abord les techniques d’exécution en mode normal.

2.1 Déboguage en mode « normal » L’une des fonctions que nous utilisons dans ce mode est CCoonnssoollee..WWrriitteeLLiinnee(()) car elle permet d’afficher du texte à la console. Lors du développement d’applications, cette fonction est très pratique. Exemple :

Console.WriteLine("MaFonction () est maintenant appelée"); MaFonction(); Console.WriteLine("MaFonction () a été maintenant appelée");

Une méthode efficace qui risque cependant de saturer la sortie écran. Pour éviter cela, vous pouvez diriger le texte vers un autre emplacement : la fenêtre Sortie de Visual Studio.

Dans le chapitre 1, nous avons rapidement abordé la fenêtre Sortie qui, par défaut, se trouve dans la partie inférieure de l’environnement de développement VS. Cette fenêtre affiche des informations relatives à la compilation et à l’exécution du code, comme les erreurs de compilation, par exemple.

2.2 Afficher des informations de déboguage utiles L’affichage d’informations dans la fenêtre Sortie lors de l’exécution de l’application est simple. Il suffit de remplacer les appels de Console.WriteLine() par des appels de la fonction de débogage appropriée. Pour cela, vous pouvez utiliser deux fonctions distinctes :

•• DDeebbuugg..WWrriitteeLLiinnee(());; •• TTrraaccee..WWrriitteeLLiinnee(());;

Attention : Afin de pouvoir utiliser ces fonctionnalités, il nous faut importer l'espace de nom appelé SSyysstteemm..DDiiaaggnnoossttiiccss. Ces commandes jouent le même rôle à la différence que DDeebbuugg..WWrriitteeLLiinnee(()) ne fonctionne que pour les versions de débogage alors que TTrraaccee..WWrriitteeLLiinnee(()) fonctionne également pour les versions de production. En fait, la commande DDeebbuugg..WWrriitteeLLiinnee(()) ne sera pas traitée lors de la compilation de la version de production. Elle disparaîtra simplement lors de la compilation, ce qui présente certainement des avantages (comme celui d’obtenir des fichiers compilés de taille inférieure). Nous pouvons en effet générer deux versions d’une même application à partir d’un seul fichier source. La version de débogage affiche toutes sortes d’informations de diagnostic, qui, dans la version de production, sont masquées à l’utilisateur. Outre les fonctions WWrriitteeLLiinnee(()), vous devez connaître un certain nombre d’autres fonctions d’affichage. Il existe un certain nombre de fonctions équivalentes à CCoonnssoollee..WWrriittee(()) :

•• DDeebbuugg..WWrriittee(());; • TTrraaccee..WWrriittee(()).

95

Page 96: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Ces deux fonctions emploient la même syntaxe que les fonctions WWrriitteeLLiinnee(()) (un ou deux paramètres ainsi qu’un message et une catégorie optionnelle), mais diffèrent de celle-ci car elles n’ajoutent pas de caractères fin de ligne. Notez également les commandes suivantes :

•• DDeebbuugg..WWrriitteeLLiinneeIIff(());; •• TTrraaccee..WWrriitteeLLiinneeIIff(());; •• DDeebbuugg..WWrriitteeIIff(());; •• TTrraaccee..WWrriitteeIIff(())..

Chacune d’elle possède les mêmes paramètres que ses homologues sans « If », avec, en plus, un paramètre obligatoire supplémentaire en tête de liste. Ce paramètre prend une valeur booléenne (ou une expression évaluant une valeur booléenne). La fonction n’affiche le texte que si cette valeur est ttrruuee. Ces fonctions permettent d’afficher du texte sous certaines conditions dans la fenêtre Sortie. Par exemple, nous pourrions avoir besoin d’afficher des informations de débogage dans certaines conditions correspondant chacune à une intrusion DDeebbuugg..WWrriitteeLLiinneeIIff(()) précise dans le code. Si la condition n’est pas remplie, les informations ne s’afficheraient pas à la fenêtre Sortie.

2.3 Déboguage en mode ‘point d’arrêt’ ou pas à pas

2.3.1 Entrer en mode Point d’arrêt Le moyen le plus simple de basculer en mode d’arrêt est d’appuyer sur le bouton Pause alors que l’application s’exécute dans VS. Ce bouton se trouve dans la barre d’outils Debug qu’il est recommandé d’ajouter aux autres barres d’outils qui s’affichent par défaut dans VS. La barre d’outils qui apparaît se présente ainsi :

Lors de l’exécution d’une application, la barre d’outils se présente ainsi :

Les trois boutons qui étaient grisés sont à présent disponibles et permettent de :

• Suspendre l’application pour basculer en mode point d’arrêt ; • Arrêter complètement l’application (pour la quitter sans entrer dans le mode point d’arrêt) ; • Redémarrer l’application.

La suspension de l’application est probablement le moyen le plus simple de basculer dans le mode point d’arrêt, mais elle ne permet pas de choisir précisément la ligne où l’arrêt va survenir. Il est préférable d’utiliser des points d’arrêt.

96

Page 97: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

2.3.2 Définir des point d’arrêt dans le code Un point d’arrêt est un marqueur qui, placé dans le code source, permet de basculer automatiquement dans le mode arrêt. Il peut être configuré pour basculer dans le mode arrêt :

• Dès que le point d’arrêt est atteint ; • Si une expression booléenne est évaluée à true ; • Lorsque le point d’arrêt est atteint un certain nombre de fois ; • Puis interrompre l’exécution du programme au point d’arrêt chaque fois que change la valeur de la

variable qui lui est associée. Notez que les points d’arrêts ne sont utilisables qu’avec les programmes dans les constructions en mode débogage. Si vous compilez une version release, tous les points d’arrêt seront ignorés. Pour ajouter un point d’arrêt simple, il suffit de cliquer sur la zone grise à gauche de la ligne où vous souhaitez le placer. Le point d’arrêt est alors symbolisé par n cercle rouge en regard de la ligne, qui est alors mise en évidence. Les informations relatives aux points d’arrêt d’un fichier source sont également consultables par l’intermédiaire de la fenêtre Points d’arrêt. Pour l’activer, sélectionnez "Déboguer | Fenêtre | Points d’arrêt". La fenêtre suivante apparaît alors dans la partie inférieure de l’écran, au même endroit que les fenêtres "Liste des tâches" et "Sortie":

Pour désactiver un point d’arrêt, supprimez la marque dans la marge (le cercle rouge est alors vide), supprimez le point d’arrêt ou éditez les propriétés de celui-ci. "Condition de point d’arrêt" et "Nombre d’accès à un point d’arrêt" font partie des deux propriétés les plus utiles. Pour éditer un point d’arrêt, il suffit de cliquer-droit dessus (dans le code ou dans cette fenêtre) et de sélectionner l’option Propriétés. Trois onglets, Fonction, Fichier et Adresse, permettent alors de modifier l’emplacement du point d’arrêt.

97

Page 98: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Dans Adresse, nous pouvons associer une adresse mémoire absolue au point d’arrêt. Les boutons Condition de point d’arrêt et Nombre d’accès à un point d’arrêt permettent de modifier les deux propriétés indiquées précédemment. Si vous sélectionnez le bouton Condition d'un point d’arrêt, la boîte de dialogue suivante apparaît :

Nous pouvons alors taper une expression booléenne mettant en œuvre des variables dans la portée du point d’arrêt. Si vous sélectionnez le bouton Nombre d’accès à un point d’arrêt, la boîte de dialogue suivante apparaît :

Il est alors possible de spécifier le nombre de passages au-delà duquel le point d’arrêt sera activé. La liste déroulante propose les options suivantes :

• toujours s’arrêter • s’arrêter lorsque le nombre d’accès est égal à .. • s’arrêter lorsque le nombre d’accès est un multiple de . • s’arrêter lorsque le nombre d’accès est supérieur ou égal à ..

Cette option est très pratique dans les traitements longs. Il serait en effet fastidieux de devoir arrêter et redémarrer un programme 5 000 fois, par exemple, avant de pouvoir afficher la valeur d’une variable spécifique.

98

Page 99: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Le nombre de points d'arrêts que vous pouvez créer dans un programme n'est pas limité par Visual Studio. En général, la création de deux ou trois points d'arrêt et le parcours du code en pas à pas permet d'identifier rapidement les erreurs de logique.

2.3.3 Autres moyens d’activer le mode arrêt Le mode Arrêt peut également être activé dans les deux situations suivantes : quand une exception non gérée est levée (cette notion est traitée à la partie consacrée à la gestion des erreurs, plus loin) et quand une assertion est générée. Les assertions sont des instructions qui interrompent l’exécution d’une application, en affichant un message personnalisé. Lors du développement, elles permettent de s’assurer que le programme fonctionne comme prévu. Supposons que la valeur d’une variable donnée doive être inférieure à 10. Une assertion permettrait de vérifier la condition et d’afficher un message si la valeur atteint ou excède 10. Lorsqu’une assertion se produit, il est possible de quitter prématurément le programme (option Abort), de basculer dans le mode Arrêt (option Retry) ou de poursuivre le traitement comme si de rien n’était (option Ignore). Comme pour les fonctions de débogage étudiées précédemment, il existe deux versions de la fonction d’assertion :

•• DDeebbuugg..AAsssseerrtt(());; •• TTrraaccee..AAsssseerrtt(());;

La fonction DDeebbuugg..AAsssseerrtt(()) n’est pas prise en charge dans les applications de production. Ces fonctions acceptent trois paramètres. Le premier est une valeur booléenne qui déclenche l’assertion lorsqu’elle est égale à false. Le deuxième et le troisième sont des paramètres chaînes permettant d’afficher des informations dans une boîte de dialogue contextuelle et dans la fenêtre Sortie. L’exemple précédent nécessiterait un appel de fonction tel que celui-ci : Debug.Assert(myVar < 10, "myVar est >= 10", "Assertion atteinte dans MaFonction()"

ou encore Trace.Assert(myVar < 10, "myVar est >= 10", "Assertion atteinte dans MaFonction()"

Nous pourrions, par exemple, fournir une brève description de l’erreur dans la première chaîne, et des instructions dans la seconde. Si l’assertion se produit, l’utilisateur verra la apparaître une boîte de dialogue avec les deux messages "myVar <=10" et Assertion Atteinte dans MaFonction" affichés, ainsi que les trois boutons "Abort", "Retry" et "Ignore". Si l’utilisateur appuie sur le bouton Retry de Visual Studio en version release, il ne verra pas le code mais ces instructions de langage assembleur qui ne lui parleront pas beaucoup.

99

Page 100: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3. Contrôler le contenu des variables Le contrôle du contenu des variables est une exemple d’opération difficile que Visual Studio simplifie. Le moyen le plus aisé de contrôler la valeur d’une variable est de survoler le nom de cette dernière avec la souris dans le code. alors que nous sommes en mode point d'arrêt. Des informations relatives à la variable, telles que sa valeur, apparaissent dans une info-bulle jaune.

3.1 La fenêtre « Variables locales » Toutes les fenêtres fonctionnent plus ou moins de la même façon. Elles comportent différentes fonctionnalités supplémentaires selon le contexte. En général, chaque fenêtre comporte une liste de variables avec des informations relatives à leur nom, leur valeur et leur type. Les symboles + et – associés aux variables plus complexes, comme les tableaux, permettent de développer ou de masquer leur contenu dans l’arborescence.

Cette vue permet également de modifier le contenu des variables, ce qui est pratique si l’affectation de valeurs n’a pas lieu dans le code. Il suffit pour cela de taper une nouvelle valeur dans la colonne Valeur de la variable à éditer. Cette technique est très pratique pour tester des scénarios de modifications de valeurs, par exemple.

3.2 La fenêtre « Recherche » D’un nombre maximal de quatre, la fenêtre Recherche permet de contrôler des variables ou expressions spécifiques impliquant des variables spécifiques. Pour utiliser une fenêtre Recherche, il suffit de taper le nom de la variable ou de l’expression dans la colonne Nom et d’observer les résultats. Notez que toutes les variables d’une application ne sont pas visibles simultanément, et sont signalées comme telles dans la fenêtre Résultats de la recherche.

100

Page 101: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Pour ajouter des variables dans une fenêtre Recherche, il suffit de les faire glisser à partir du code source. Pour ajouter d’autres fenêtres, nous pouvons utiliser les options Déboguer | Fenêtre | Recherche | Résultats de la recherche permettant d’activer et de désactiver les quatre fenêtres autorisées. Chaque fenêtre peut contenir un jeu particulier d’inspecteurs sur les variables et les expressions, ce qui facilite le regroupement de variables associées et leur accès. A l’instar des fenêtres Résultats de la recherche, la fenêtre QuickWatch permet d’accéder rapidement à des informations détaillées relatives à une variable directement dans le code source. Pour cela, il suffit de cliquer droit sur la variable à interroger et de sélectionner l’option QuickWatch. Le plus souvent, les fenêtres Résultats de la recherche standard permettent d’effectuer les mêmes opérations. Il est important de noter que les inspecteurs sont conservés d’une exécution d’application à l’autre. Visual Studio mémorise ces points d’arrêt entre les sessions.

3.3 Différents mode de pas à pas Nous avons vu comment examiner ce qui se passe au point exact où VS bascule en mode Arrêt. Nous allons à présent découvrir comment exécuter les instructions pas à pas. Les commandes de pas-à-pas sont disponible via la barre d'outils Debug, le menu Debug, ou encore les raccourcis clavier. Voici les trois mode de pas-à-pas en C#

• Pas-à-pas détaillé (F11) : exécute l'instruction en cours et passe à la suivante • Pas-à-pas principal (F10): même opération que ci-dessus mais les blocs imbriqués ne sont pas

détaillés. • Pas à pas sortant (Shift+F11): exécute le bloc de code en cours jusqu'à la fin et repasse en mode

Arrêt. L'utilisation de et le parcours du code avec ces différents modes de pas-à-pas est particulièrement bien adaptée à la détection d’erreurs sémantiques. Elle permet d’aller directement à l’emplacement suspect et de vérifier si les erreurs se produisent.

3.4 La fenêtre « Command » La fenêtre Fenêtre Commande possède deux modes. Le mode Commande permet d’effectuer des opérations dans VS sans passer par la barre de menus. Le mode Immédiat permet d’exécuter du code entre des instructions standard et d’évaluer des expressions. En mode Commande, chaque ligne commence par le signe supérieur à (>). Pour basculer en mode immédiat, il suffit de taper iimmmmeedd dans cette fenêtre et d’appuyer sur Entrée, puis de taper >>ccmmdd et d’appuyer sur EEnnttrrééee pour revenir dans le mode précédent. Nous nous concentrerons sur le mode Immédiat, car le mode Commande n’est utile que pour les opérations complexes. L’utilisation la plus simple de cette fenêtre consiste à évaluer des expressions, de façon « instantanée » comme dans les fenêtres Rechercher. Pour cela, il suffit de taper une expression et d’appuyer sur Entrée. Les informations demandées s’affichent alors. Par exemple : NNoommVVaarriiaabbllee ((NNoommVVaarriiaabbllee11 ** NNoommVVaarriiaabbllee22)) Nous pouvons également modifier le contenu des variables. Exemple : NNoommVVaarriiaabbllee == 1100

101

Page 102: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

3.5 La fenêtre « Pile des appels » Il s’agit de la dernière fenêtre que nous étudierons ici. Elle indique le nom de la fonction en cours d’exécution, la fonction d’appel ainsi que les imbrications d’appels de fonctions. Le point d’appel est également enregistré. Cette fenêtre est particulièrement utile lorsque des erreurs sont détectées en premier, car elle permet de voir ce qui s’est produit immédiatement avant et ce qui a causé l’erreur.

Cette fenêtre affiche parfois des informations difficiles à comprendre. Il arrive que des erreurs se produisent hors des applications, dans des fonctions externes. Dans ce cas, la liste d’informations concerne ces fonctions et la pile des appels comprend des entrées vers des fonctions compilées. A noter que l'objet EExxcceeppttiioonn possède une propriété SSttaacckkTTrraaccee qui permet également de consulter la pile des appels sans disposer de Visual Studio .net.

102

Page 103: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4. Gestion des Erreurs

4.1 Les exceptions Une exception est une erreur générée lors de l’exécution du code ou lors de l’exécution d’une fonction. Nous avons déjà abordé les exceptions dans ce cour. Un moyen simple d'en générer une est de lire un élément de tableau hors des bornes de celui-ci. Exemple : int[] myArray = {1, 2, 3, 4}; int item = myArray[10];

Ceci génère le message d’exception suivant et met fin à l’application : AAnn uunnhhaannddlleedd eexxcceeppttiioonn ooff ttyyppee ««SSyysstteemm..IInnddeexxOOuuttOOffRRaannggeeEExxcceeppttiioonn»» ooccccuurreedd iinn <<nnoommFFiicchhiieerr>> <<nnoommFFiicchhiieerr>> est le nom du fichier comportant l’exception. Les exceptions sont définies dans des espaces de noms. Elles portent généralement un nom correspondant à leur rôle et à l’erreur traitée. Dans notre exemple, l’exception générée s’appelle SSyysstteemm..IInnddeexxOOuuttOOffRRaannggeeEExxcceeppttiioonn, nom qui signifie que l’indice spécifié se trouve en dehors de l’intervalle autorisé dans mmyyAArrrraayy. Ce message n’apparaît et l’application ne prend fin que si l’exception n’est pas gérée. Que signifie exactement « gérer » une exception ?

4.2 La structure « try..catch..finally » Le langage C# comporte une syntaxe pour la gestion structurée de exceptions. Les mots-clés permettent de signaler le bloc d’instructions à exécuter lorsqu’une exception survient. Il s’agit de ttrryy, ccaattcchh et ffiinnaallllyy. Chaque mot-clé désigne un bloc de code particulier dont les instructions doivent nécessairement s’exécuter séquentiellement. La structure de base est la suivante : try { // Code pouvant générer une exception } catch (<typeException> e) { // Gestion de l'exception } finally { // Code toujours exécuté que l'exception se soit produite ou pas. }

Il est également possible d’insérer un bloc ttrryy et un bloc ffiinnaallllyy (sans bloc ccaattcchh) ou un bloc ttrryy et plusieurs blocs ccaattcchh. Si un ou plusieurs ccaattcchh figure(nt) dans le programme, le bloc ffiinnaallllyy est facultatif. Autrement, il est obligatoire.

103

Page 104: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Les blocs sont utilisés comme suit :

• ttrryy : contient le code susceptible de lever des exceptions, ce verbe signifiant « générer » ou « causer » en termes d’exceptions ;

• ccaattcchh : contient le code à exécuter lorsque des exceptions sont levées. Les blocs ccaattcchh répondent

à des types d’exceptions spécifiques (comme SSyysstteemm..IInnddeexxOOuuttOOffRRaannggeeEExxcceeppttiioonn) à l’aide de <<eexxcceeppttiioonnTTyyppee>>,, ce qui permet de définir plusieurs blocs ccaattcchh dans une même application. Il est possible d’omettre ce paramètre pour définir un bloc ccaattcchh générique destiné à traiter toutes les exceptions ;

• ffiinnaallllyy : contient du code qui doit toujours s’exécuter, soit après le bloc ttrryy si aucune exception

ne survient, après un bloc ccaattcchh si une exception est gérée, soit simplement avant qu’une exception non gérée mette fin à l’application (le fait que ce bloc soit traité à ce moment précis est la raison de son existence ; autrement, nous pourrions placer le code après le bloc).

La séquence d’évènements après le déclenchement d’une exception dans un bloc se déroule ainsi :

• le bloc ttrryy se termine à l’emplacement où est survenue l’exception ; • si un bloc ccaattcchh existe, le programme vérifie si le bloc correspond au type d’exécution levée. Dans le

cas contraire, le bloc ffiinnaallllyy s’exécute (il doit être défini en l’absence de blocs ccaattcchh) ; • s’il n’existe pas de correspondance alors qu’un bloc ccaattcchh existe, un contrôle s’effectue sur les

autres blocs ccaattcchh ; • si un bloc ccaattcchh correspond au type d’exception, le code qu’il contient s’exécute, et le code du bloc

ffiinnaallllyy s’exécute ensuite ; • si aucun bloc ccaattcchh ne correspond au type d’exception, le bloc ffiinnaallllyy s’exécute directement.

Mettre en œuvre une gestion d’erreurs centralisée Il est intéressant de noter que les exceptions non gérées remontent la pile des appels jusqu'à ce qu'elles trouvent un bloc ccaattcchh permettant de les traiter. On appelle ce comportement le "bubbling" (pour bubbles qui veut dire "bulles") car les exceptions remontent la pile des appels comme des bulles remontent à la surface de l'eau. Il est donc tout-à-fait possible de gérer les exceptions aun niveau que l'on souhaite et même mettre en œuvre une gestion d'erreurs centralisée à un point précis de l'application.

104

Page 105: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

4.3 Lister et configurer des exceptions .NET Framework comporte un ensemble de types d’exceptions que vous pouvez lever et gérer dans un même programme ou lever dans un programme et gérer dans un autre, plus complexe. VS propose une boîte de dialogue pour examiner et éditer les exceptions disponibles.

4.5 La Fenêtre Exceptions Dans cette fenêtre, les exceptions sont classées par catégorie et par espace de noms de bibliothèque .NET. Pour afficher leur liste disponible dans l’espace de noms SSyysstteemm, développez la branche de l'arbre Common Language Runtime Exceptions, puis la branche System.

Chaque exception peut être configurée à l’aide des boutons radio situés dans la partie inférieure de la boîte de dialogue. La plupart sont réglés par défaut sur "Useparent setting", ce qui signifie qu’elles utilisent les options de niveau catégorie (toutes visibles dans l’illustration précédente). Nous pouvons utiliser la première option, Lorsque l’exception est levée, pour créer une rupture dans le débogueur, y compris pour les exceptions gérées. La seconde option permet de ne pas tenir compte des exceptions non gérées, avec toutes les conséquences qui en découlent.

105

Page 106: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Chapitre 5 - Concepts Orientés Objet

5.1 Constructeurs Chaque classe possède ce qui s'appelle un constructeur. Un constructeur est appelé lors de la création d'une instance de la classe à l'aide du mot-clé new. Par exemple, lorsque nous écrivons le code suivant : object o = new object();

Le constructeur de la classe System.Object est appelé.

5.1.1 Par défaut Si une classe n'implémente pas explicitement un constructeur, le constructeur dit par défaut est appelé (en fait, le constructeur de la classe object est appelé). Par exemple, on peut tout à fait définir une classe : public class Test { public string Valeur = ""; }

et instancier cette classe avec : Test MyTest = new Test();

Il est également possible de définir explicitement un constructeur sans paramètres comme ceci : public class Test {

public string Valeur = ""; public Test() { Valeur = "Une Valeur"; } }

et de l'instancier de la même façon, auquel cas le constructeur Test() sera exécuté.

5.1.2 Paramétrés On peut tout à fait définir plusieurs constructeurs (surcharge) ou ne définir qu'un constructeur avec des paramètres (auquel cas, la classe ne pourra plus être instanciée en utilisant son constructeur par défaut). Un constructeur paramétré sera donc une fonction publique même nom que la classe avec des paramètres.

5.1.3 Statiques Les constructeurs statiques sont une nouveauté de C#. Ils permettent d'initialiser les variables statiques contenues dans la classe. En effet, les variables statiques peuvent être initialisées lors de leur déclaration (comme la variable j dans cette exemple), mais peuvent également être initialisées par un constructeur statique.

106

Page 107: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Notons que les constructeurs statiques sont exécutés au premier appel d'un membre statique de la classe. public class TestStaticConstructor { public static int i; public static int j = 20; static TestStaticConstructor() { i = 10;

} }

5.1.4 Appeler d'autres constructeurs depuis un constructeur. Il est possible d'appeler d'autres constructeurs depuis un constructeur. Pour cela, on dispose de la syntaxe suivante : public class BaseClass { public string Nom, Prenom; public BaseClass () { Nom = "NomVide"; Prenom = "PrenomVide"; } public BaseClass (string nom) : this () { Nom = nom; } public BaseClass (string nom, string prenom) : this (nom) { Prenom = prenom; } }

Iorsque nous instancions la classe avec la syntaxe suivante : BaseClass x = new BaseClass ("aa","bb");

Les trois constructeurs sont appelés dans cet ordre : BBaasseeCCllaassss(()) BBaasseeCCllaassss((ssttrriinngg nnoomm)) BBaasseeCCllaassss((ssttrriinngg nnoomm,, ssttrriinngg pprreennoomm))

5.1.5 Appeler des constructeurs de la classe de base Il est également possible d'appeler des constructeurs de la classe de base dans une hiérarchie d'héritage en utilisant le mot-clé base à la place du mot-clé this. public class BaseClass { public string Nom, Prenom;

107

Page 108: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

public BaseClass() { Nom = "NomVide"; Prenom = "PrenomVide"; } public BaseClass(string nom) : this () { Nom = nom; } public BaseClass(string nom, string prenom) : this (nom) { Prenom = prenom; } } public class DerivedClass : BaseClass { public int Age; public DerivedClass(string nom, string prenom, int age) : base (nom, prenom) { Age = age;} }

Dans ce cas, si nous instancions DerivedClass de cette manière : DerivedClass x = new DerivedClass("aa","bb",10);

Les constructeurs sont appelés dans cet ordre : BBaasseeCCllaassss(()) BBaasseeCCllaassss((ssttrriinngg nnoomm)) BBaasseeCCllaassss((ssttrriinngg nnoomm,, ssttrriinngg pprreennoomm)) DDeerriivveeddCCllaassss((ssttrriinngg nnoomm,, ssttrriinngg pprreennoomm,, iinntt aaggee)) Il est important de noter que les constructeurs ne sont pas hérités. Dans l'exemple de code précédent, il ne sera donc pas possible d'instancier la classe DerivedClass avec un constructeur sans paramètres.

108

Page 109: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.2 Destructeurs Un destructeur est une méthode d'une classe qui sera appelée quand la les objets du type de cette classe seront détruits en mémoire (d'où le nom destructeurs). Les destructeurs sont couramment utilisés en C++, mais en C#, leur utilisation est moins fréquente à cause de la façon dont le Framework .net gère les ressources en mémoire.

5.2.1 Syntaxe Pour implémenter un destructeur, il suffit de créer une méthode de nommée ~NomClasse() comme ceci : public class Test {

~Test() { Console.WriteLine("Destructeur Appelé"); } }

Cependant, le Framework .net ne garantit pas le moment exact auquel sera appelé le destructeur d'une classe. Ne placez donc pas de code dans un destructeur si ce code doit s'exécuter à un moment précis !

5.2.2 Notion de Garbage Collector et Finalisation non-déterministe COM utilisait le comptage de références pour détruire les objets en mémoire, c'est-à-dire que dès lors qu'un objet n'était plus référencé par aucun autre, il était détruit. Le Framework .net ne fonctionne pas de cette manière. Le Framework .net fournit un GarbageCollector ou "ramasse-miettes". Le GarbageCollector est un objet qui va périodiquement vérifier tous les objets qui ne sont plus référencés et les détruire. Cependant, il n'est pas possible de prédire quand le GarbageCollector va se déclencher et il n'est donc pas possible de prédire exactement quand les objets vont être détruits. On appelle cela la finalisation non-déterministe. Note : on peut cependant explicitement ordonner au Garbage Collector de détruire les objets qui doivent l'être et d'ainsi récupérer la mémoire qui leur était allouée en utilisant la méthode Collect() comme ceci : GC.Collect(); Cette opération est cependant assez coûteuse en temps et en ressources et il n'est pas conseillé d'en faire un usage fréquent.

109

Page 110: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.2.3 Interface IDisposable et Méthode Dispose. On utilisera donc plutôt la pattern "Dispose" et l'interface IDIsposable pour nettoyer nos objets. L'interface IDisposable fournit une méthode Dipose que nous devrons implémenter pour effectuer le nettoyage des objets non managés éventuellement présents dans nos classes. Il est conseillé de préférer la pattern Dispose et l'interface IDisposable à l'implémentation de destructeurs pour nettoyer les objets. Regardons la façon d'implémenter l'interface IDisposable dans une classe : public class Test : IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { // Nettoyage des objets managés } // Nettoyage des objets non-managés } ~Test() { Dispose(false); } }

La version surchargée de Dispose qui prend un paramètre booléen est la méthode qui effectue réellement le nettoyage des objets. Dispose(bool) est appelée à la fois par le destructeur et par la méthode IDisposable.Dispose() afin de s'assurer que le nettoyage ne s'effectue que dans un seul endroit. Le paramètre de Dispose(bool) indique si cette méthode a été invoquée par le destructeur ou par Dispose(). Aucun appel à Dispose(bool) ne doit figurer par ailleurs dans votre code. Le principe est le suivant :

- Si du code client appelle IDisposable.Dispose(), ce client indique que toutes les ressources de l'objet (managées et non managées) doivent être nettoyées

- Si un destructeur est invoqué, toutes les ressources doivent, en principe, être nettoyées. Cependant,

dans ce cas, le destructeur aura été appelé par le GarbageCollector. Il reste donc à effectuer explicitement le nettoyage des ressources non-managées. Il existe une autre raison de ne pas se référer à des objets managés depuis le code invoqué dans le destructeur qui est que , comme il n'est pas possible de prédire dans quel ordre les objets sont détruits, les objets managés concernés pourraient très bien déjà avoir été détruits.

Examinons le code précédent : ce qui se passe en dernier dans la méthode Dispose() est un appel à GC.SuppressFinalize(this). La méthode SuppressFinalize indique au GarbageCollector que le destructeur d'une classe n'a plus besoin d'être appelé, ce qui rend le processus de nettoyage de la mémoire plus efficace (car il se produit en une seule passe au lieu de deux). Comme Dispose() aura déjà effectué le nettoyage nécessaire, le destructeur n'aura plus rien à faire.

110

Page 111: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

En procédant ainsi, vous avez une sécurité accrue pour le nettoyage de vos objets. Si le code client se souvient d'appeler Dispose(), les ressources sont nettoyées en temps voulu. Si par contre le code client oublie d'appeler Dispose(), le destructeur est appelé quand l'objet est nettoyé.

5.6 Héritage L'héritage est l'un des concepts clé de la programmation objet. En C#, et plus généralement dans tous les langages du Framework .Net, seul l'héritage simple est supporté (c'est-à-dire qu'une classe ne peut hériter que d'une seule classe directement).

5.6.1 Héritage de classes Le concept d'héritage permet à une classe B d'hériter de toutes les fonctionnalités définies dans une classe A. Voici la syntaxe permettant à la classe ClassB d'hériter des membres de la classe ClassA. public class ClassB : ClassA

5.6.2 le mot-clé this Le mot-clé this permet de se référer à l'instance en cours de la classe depuis l'intérieur de la classe. Par exemple, si une méthode d'une classe A doit passer à une méthode d'une classe B une référence vers l'instance en cours, il peut le faire en utilisant le mot-clé this avec la syntaxe suivante : public class ClassA { public void PasserInstance() { ClassB.Test(this); } } public class ClassB { static public void Test(ClassA uneInstance) { // Code utilisant l'instance passée } }

Attention : C'est une erreur que d'utiliser le mot-clé this depuis le code d'un membre statique.

5.6.3 le mot-clé base Le mot-clé base est utilisé dans le code d'une classe dérivée pour se référer aux membres de sa classe de base. public class ClassBase { public string GetInfos()

111

Page 112: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

{ return "Une Chaîne"; }

} public class ClassDerived : ClassBase { public string Test() { return base.GetInfos(); } }

Dans la classe ClassDerived, la méthode publique Test effectue un appel à sa classe de base ClassBase et appelle sa méthode GetInfos(). NOTE: Notez que le mot-clé base est également utilisé dans la déclaration des constructeurs de classes pour faire appel à un constructeur d'une classe de base.

112

Page 113: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.6.4 Redéfinition de méthodes Le mot clé virtual est utilisé pour modifier la déclaration d'un méthode ou d'une propriété, auquel cas la méthode ou propriété est appelé membre virtuel. L'implémentation d'un membre virtuel peut être changée par un membre de même nom marqué avec le modificateur override dans une classe dérivée. Quand une méthode virtuelle est invoquée, le type réel (pas son type de déclaration) de l'objet est parcouru pour voir s'il contient un membre marqué comme override, redéfinissant la méthode. Le membre redéfini dans la classe la plus dérivée est alors appelé (ce membre peut être le membre original si aucune classe dérivée n'a redéfini le membre). Par défaut, les membres ne sont pas virtuels et l'on ne peut redéfinir un membre non-virtuel. On ne peut redéfinir un membre de classe marque comme static, abstract ou override. public class ClassBase { public virtual string Test() { return "ClassBase : Test"; } } public class ClassDerived : ClassBase { public override string Test() { return "ClassDerived : Test()"; } } public class Start { static void Main() { ClassBase A = new ClassBase(); ClassBase B = new ClassDerived() Console.WriteLine(A.Test()); Console.WriteLine(B.Test()); } }

Ce code donne la sortie suivante : CCllaassssBBaassee :: TTeesstt(()) CCllaassssDDeerriivveedd :: TTeesstt(()) Alors que les deux types de déclaration de A et B sont bien de type ClassBase. Ceci illustre ce que nous disions au début de cette section, à savoir que c'est bien l'implémentation de la méthode contenue dans le type réel (le "run-time type") qui est exécutée et non celle contenue dans son type de déclaration.

113

Page 114: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.6.4 Masquage de méthodes De même que nous pouvons (avec le modificateur override) redéfinir une méthode d'une classe de base, nous pouvons également "masquer" l'implémentation d'une méthode dans une classe de base par une nouvelle implémentation dans une classe dérivée. Le masquage de noms au travers de l'héritage se produit lorsqu'une classe redéclare un nom dont il a hérité d'une classe de base. Ceci se fait avec le mot-clé new comme démontré dans l'exemple suivant : class Base {

public void F() {} } class Derived: Base { public new string F() {return "";} }

Le but du mot-clé new est d'indiquer qu'il s'agit bien d'une nouvelle implémentation de la méthode F() (qui d'ailleurs, ne prend pas les mêmes paramètres).

5.7 Interfaces Une interface est un contrat ! Une classe ou structure implémentant une interface doit adhérer à ce contrat, c'est-à-dire fournir une implémentation pour tous les membres définis dans le corps de l'interface. Une Interface peut hériter d'autres interfaces, et une même classe peut implémenter plusieurs interfaces. Les interfaces peuvent contenir des méthodes, des propriétés, des évènements et des indexeurs. L'interface elle-même ne fournit jamais d'implementation pour les membres qu'elle contient mais simplement définit les membres que devront fournir (et donc implémenter) les classes et/ou structures qui implémenteront cette interface. Voici la syntaxe pour déclarer une interface : interface IControl { void Paint(); }

Cette interface définit un membre Paint() ce qui implique que toutes les classes et structures implémentant cette interface devront fournir ce membre.

114

Page 115: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.7.2 Implémentation d'interfaces Quand une classe implémente une interface, elle doit le signaler dans sa déclaration comme ceci: ppuubblliicc ccllaassss LLiioonn :: IICCaarrnniivvoorree Si la classe hérite d'une autre classe, il nous faut d'abord indiquer le nom de la classe de base, puis le non de la ou des interfaces que la classe implémente : ppuubblliicc ccllaassss LLiioonn :: AAnniimmaall,, IICCaarrnniivvoorree,, IIPPrreeddaatteeuurr Regardons l'exemple d'une classe imaginaire TextBox implémentant l'interface IControl. interface IControl { void Paint(); } class TextBox: IControl { public void Paint() {// Code de la méthode...} }

5.7.2 Polymorphisme par les interfaces Les interfaces sont un autre moyen d'implémenter le polymorphisme. Alors que l'héritage représente une relation que nous pourrions énoncer comme "est un", les interfaces définissent une relation que nous pourrions appeler "peut se comporter en tant que". Exemple : Par exemple supposons que nous ayons défini une classe Lion, une classe Aigle et une classe Crocodile et que toutes ces classes héritent de la classe Animal. Nous pourrions tout à fait créer un tableau de type Animals et stocker dedans des références vers des objets Lion, Aigle ou Crocodile (si le type de déclaration de ceux-ci est bien Animal). C'est le polymorphisme de classe que nous avons évoque plus haut. Mais, nous constatons que ces trois classes ont des choses en commun : ce sont tous des carnivores. Nous pourrions inclure les méthodes communes à tous les carnivores dans la classe Animal mais, dans ce cas, nous ne pourrions plus faire hériter la classe Lapin de la classe Animal. Comme le langage C# ne supporte que l'héritage simple (une classe ne peut hériter que d'une seule autre classe), la solution se trouve dans les interfaces. En effet, nous constatons que les trois classes évoquées ci-dessus implémentent bien la relation d'héritage "est un" (un Lion est un Animal, un Aigle est un Animal, etc..). Mais l'usage des interface nous permet d'implémenter la relation "peut se comporter en tant que" (un Lion peut se comporter en tant que carnivore, un Aigle aussi, etc..). C'est ce que nous démontre l'exemple de code suivant :

115

Page 116: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

public class Animal { private short _Poids; public short Poids { get { return _Poids; } set { _Poids = value; } } } interface ICarnivore { string Chasser(); } public class Lion : Animal, ICarnivore { public void Rugir() { Console.WriteLine("Le Lion {0} rugit."); } public string Chasser() { Console.WriteLine("Le lion chasse des biches");} } public class Aigle : Animal, ICarnivore { public void Voler() { Console.WriteLine("L' Aigle {0} vole."); } public string Chasser() { Console.WriteLine("L' Aigle chasse des souris");} }

Nous voyons que Aigle et Lion dérivent tous deux d'Animal mais implémentent aussi l'interface ICarnivore. On peut donc les traiter comme des ICarnivore. static void Main(string[] args) { Lion UnLion = new Lion(); Aigle UnAigle = new Aigle(); ICarnivore[] Chasseurs = {UnLion, UnAigle}; foreach (ICarnivore c in Chasseurs) c.Chasser(); }

Cette façon d'implémenter le polymorphisme avec les interfaces est extrêmement pratique et permet de pallier les limitations du polymorphisme d'héritage.

116

Page 117: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.7.3 Héritage d'interfaces Une interface peut tout-à-fait hériter d'une autre interface. Dans l'exemple de code suivant, l'interface ITextBox hérite de l'interface IControl. Toute classe implémentant l'interface ITextBox devra donc fournir une implémentation des membres de ITextBox et des membres de IControl. interface IControl { void Paint(); } interface ITextBox: IControl { void SetText(string text); } class TextBox: ITextBox { public void Paint() {...} public void SetText(string text) {...} }

Le polymorphisme d'interfaces que nous avons étudié dans la section précédente s'applique fort bien aux hiérarchies d'héritage d'interfaces. Ici, nous pourrions tout à fait stocker des objets de type TextBox dans un tableau de type IControl ou dans un tableau de type ITextBox.

117

Page 118: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.7 Classes

5.7.1 Classes abstraites Le mot-clé abstract est utilisé pour indiquer qu'une classe est incomplète et qu'elle ne doit être utilisée qu'en tant que classe de base. Un classe abstraite diffère d'une classe non-abstraite par les comportements suivants :

- Une classe abstraite ne peut pas être instanciée directement. On peut cependant déclarer des variables de types de classes abstraites dès lors que l'on leur affectera soit null soit une référence vers une classe non abstraite dérivant de la classe abstraite.

- Une classe abstraite peut contenir des membres abstraits. - Une classe abstraite ne peut pas être déclarée avec le modificateur sealed.

Lorsqu'une classe non-abstraite est dérivée d'une classe abstraite, la classe non abstraite doit fournir une implémentation pour tous les membres abstraits de la classe de base, en redéfinissant ces membres abstraits. On peut considérer les classes abstraites comme un concept à mi-chemin entre les classes de base non abstraites et les interfaces en ce sens que l'on peut hériter d'elles mais qu'elles définissent également un contrat en cela que les classes dérivant d'une classe abstraite doit fournir une implémentation pour tous les membres abstraits définis dans la classe abstraite. Regardons l'exemple de code suivant : abstract class A { public abstract void F(); } abstract class B: A { public void G() {} } class C: B { public override void F() { // actual implementation of F } }

La classe abstraite A déclare une méthode abstraite F(). La classe B fournit une autre méthode G(), mais, comme elle ne fournit pas d'implémentation pour sa classe de base, elle doit également être abstraite. La classe C redéfinit (override) la méthode F() et fournit son implémentation. Comme la classe C ne déclare pas de membres abstraits, on peut déclarer la classe C comme non abstraite.

118

Page 119: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

5.7.2 Classes sealed Si l'on souhaite empêcher que l'on puisse hériter d'une classe, on peut déclarer celle-ci avec le mo-clé sealed. Une erreur de compilation se produit si vous essayez d'instancier une classe déclarée comme sealed. Ce mot-clé est l'équivalent du mot-clé final en Java. Une classe sealed ne peut pas être déclarée abstract. Déclarer une classe comme sealed peut être intéressant pour de nombreuses raisons, l'une d'entre elles étant la possibilité pour un développeur fournissant un composant d'empêcher les clients ayant acheté son composant de dériver leur propres classes des classes du composant.

5.7.3 Niveau d'accessibilité des classes et des membres. Les classes peuvent être déclarées avec différents modificateurs d'accès qui définiront leurs possibilités d'accès et d'instanciation depuis du code client et depuis d'autres assemblys. les différents niveaux d'accessibilité pour les classes sont définis par les modificateurs d'accès suivants :

• publique (mot-clé public) qui indique que la classe est publique • privée (mot-clé private) qui indique que la classe est privée (ce niveau est seulement disponible pour

les classe imbriqueés dans d'autres classes).

• interne (mot-clé internal) indique que l'accès à la classe est restreint aux éléments contenus dans le même assembly.

La valeur par défaut pour les classes est internal. Les modificateurs d'accès possibles pour un membre peuvent être l'un des suivants :

• Public (mot-clé public) qui définit un accès non limité au membre • Protégé (mot-clé protected) qui indique que le membre est accessible dans la classe qui le contient et

aux classes dérivées de cette classe

• Interne (mot-clé internal) qui indique que l'accès au membre est limité aux élements contenus dans

le même assembly. • Interne protégé (mots-clé protected internal) qui indique que l'accès est autorisé seulement aux

éléments contenus dans le même assembly ou aux membres dérivant de la classe contenant le membre interne protégé.

• Privé (mot-clé private) qui indique que l'accès au membre est limité au type qui le contient.

119

Page 120: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

En fonction du contexte dans lequel est situé une déclaration de membre, seuls certains types de modificateurs d'accès sont permis. De plus, quand la déclaration d'un membre n'inclut pas de modificateurs d'accès, l'accès à ce membre est défini par défaut, comme dans la liste suivante :

• Les namespace sont toujours public par défaut. Aucun modificateur d'accès n'est autorisés pour une déclaration de namespace

• Les types déclarés directement dans des namespaces peuvent seulement être public ou internal.

• Les membres de classes peuvent avoir l'un des cinq modificateurs d'accès définis plus haut dans cette

section.

• Les membres des structures (struct) peuvent avoir les accessibilités suivantes : public, private ou internal.

• Les membres d'interfaces sont toujours implicitement public. Il n'est cependant pas permis d'inclure

le modificateur public pour ces membres.

• Les membres des énumérations sont toujours implicitement public. Il n'est cependant pas permis d'inclure le modificateur public pour ces membres.

120

Page 121: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Annexe 1 – Conventions de codage en C#.

1. Introduction Nous examinerons ici les recommandations écrites de Microsoft en ce qui concerne les conventions de codage en langage C#. Tout langage de développement possède généralement un style de programmation qui lui est propre. Ce style ne fait pas partie du langage lui-même mais représente un ensemble de conventions concernant le langage. Ces conventions incluent par exemple des règles de nommage des variables, la casse à utiliser selon les cas, et les modes d'utilisation des classes, méthodes et fonctions. Si la majorité des développeurs suivent les mêmes conventions, la lecture et la maintenance du code est facilitée pour tout le monde et il sera ainsi plus facile pour un développeur de comprendre le code écrit par un autre. Ces conventions sont consultables dans l'aide MSDN aux adresses suivantes : Pour les conventions générales de conception : ms-help://MS.NETFrameworkSDKv1.1/cpgenref/html/cpconnetframeworkdesignguidelines.htm Pour les conventions de nommage des éléments : ms-help://MS.NETFrameworkSDKv1.1/cpgenref/html/cpconnamingguidelines.htm Bien sûr, l'ensemble de toutes les recommandations de codage pour adopter de bonnes pratiques de programmation représente une quantité importante d'informations à "digérer". Dans le cadre de cette annexe, nous ne ferons que reprendre les points les plus importants de ces recommandations. Si vous voulez être certains que votre code suit à la lettre les recommandations de codage en vigueur, il vous est conseillé de vous reporter à la documentation MSDN.

2. Conventions de nommage Les conventions de nommage ont toujours fait l'objet de discussion passionnées entre les développeurs et architectes d'application, chacun débattant longuement des avantages et inconvénients de leurs propres méthodes. Ainsi, dans Visual Basic 6, les développeurs utilisaient une convention qui consistait à préfixer les noms de variables par une abréviation représentant le type de la variable déclarée. Par exemple, une variable de type string nommée "Nom" se serait écrite : Dim strNom as string. Les conventions dépendent cependant également des langages et plateformes utilisées. Par exemple, les développeurs C++ qui programment sur des plateformes Windows utilisent des préfixes psz ou lpsz pour indiquer des chaînes de caractères (ex: char *pszResult; ou encore char *lpszMessage;) Mais, sur des machines Unix, il n'es pas rare de voir des développeurs n'utilisant pas ces mêmes préfixes (ex: char *Result; ou encore char *Message;).

121

Page 122: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

La convention selon laquelle les noms de variables sont précédés de lettres représentant le type de donnéesest connue sous le nom de notation hongroise. Il est ainsi possible, pour un développeur, de reconnaître immédiatement le type de la variable à la lecture de son nom

. En ce qui concerne les conventions de codage en C#, nous n'utiliserons pas la notation hongroise. En effet, dans le Framework .NET, tout est objet. On ne peut donc pas préfixer les noms de variables avec un préfixe indiquant le type de données (ou alors, on ne préfixerait que les variables représentant les types de données intrinsèques). Intuitivement on peut dire que les noms devraient refléter la destination de l'élément et n'entrer en conflit avec aucun autre nom. Dans le Framework .Net, la philosophie générale de la dénomination des variables suggère que le nom de la variable devrait refléter l'emploi de l'instance de cette variable et non son type de données (par exemple Longueur est un bon nom de variable alors que ValeurEntière ne l'est pas).

3. Casse des noms d'éléments (Pascal Casing et Camel Casing) Pour résumer, on emploie deux types de casse de caractères appelés :

• Pascal Casing (Une majuscule au début de chacun des mots composant le nom d'élément). • Camel Casing (on commence le nom en minuscules, puis, une majuscule au début de chaque mot.

Exemple de Pascal Casing : WindowHeight, WriteLine Exemple de Camel Casing : windowPosition, integralHeight Il est déconseillé d'utiliser la syntaxe consistant à séparer les mots par un caractère "underscore" comme dans ("Window_Position") De même, il est déconseillé d'écrire les noms de constantes en majuscules, comme c'était le cas dans certains langages précédents (comme dans Visual Basic 4,5 et 6 par exemple). On peut également prendre en compte la portée des éléments pour savoir quelle casse (Pascal ou Camel) utiliser pour nommer un élément. En général, tous les éléments publics sont écrits en Pascal Casing alors que les éléments privés seront plutôt écrits en Camel Casing. Par exemple :

• les noms de tous les paramètres passés à une méthode devraient être en casse Camel : ppuubblliicc vvooiidd RReeccoorrddSSaallee((ssttrriinngg ssaalleessNNaammee,, iinntt qquuaannttiittyy))

• vous devriez utliser la casse Camel pour établir une distinction entre deux éléments qui, autrement

auraient exactement le même nom. Un exemple commun est celui d'une propriété encapsule un champ :

pprriivvaattee ssttrriinngg nnoommSSaallaarriiee;; ppuubblliicc ssttrriinngg NNoommSSaallaarriiee {{ ggeett

122

Page 123: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

{{ rreettuurrnn nnoommSSaallaarriiee;; }}

sseett {{ nnoommSSaallaarriiee == vvaalluuee;; }}

}} Pour ce qui est des conventions, le code précédent est acceptable. Il est important de rester attentif à la casse des éléments que vous définissez, et, dans tous les cas de figure, d'adopter une règle pour la casse et de s'y tenir. Il est pratique par exemple de savoir immédiatement que la variable nomSalarie est une variable privée, juste en analysant sa casse. En tout état de cause, le langage C# est sensible à la casse et il est donc important de porter une attention particulière aux conventions de nommage des éléments.

4. Style des Noms d'éléments. Essayez d'être cohérents dans le style que vous donnez aux noms des éléments que vous définissez. Par exemple, essayez de toujours garder dans le même ordre les noms et les verbes. Si vous appelez une méthode RechercherFichiersTexte(), nommez une autre méthode RechercherFichierImages() au lieu de FichiersImageRechercher().

5. Nommage des Namespaces (espaces de noms). Le nom des namespaces est particulièrement important dans l'organisation de votre code et peut grandement faciliter et normer la manière dont les objets communiquent entre eux. De plus, une grande attention est nécessaire (surtout si vous développez des composants réutilisables) afin d'éviter toute collision possible entre le nom complet (c.à.d. le nom de tous les namespaces contenant + le nom de l'élément) de l'un de vos éléments et le nom d'un autre élément que vous n'avez pas développé. Par exemple, si vous utilisez le même nom de namespace pour un logiciel alors que ce nom est déjà utilisé dans un autre logiciel, des problèmes de collisions de noms risquent de se poser ! De ce fait, la création d'un namespace de haut niveau (comme par exemple le nom de votre société) représente toujours une bonne solution de ce point de vue. Vous pourrez par la suite créer à l'intérieur du namespace de haut niveau, des namespaces successifs représentant la technologie, le département, ou encore la couche (couche d'accès aux données, couche métier, etc..) à laquelle sont destinées les classes contenues. Pour information, Microsoft recommande les namespaces commençant par :

<<NNoommDDeeSSoocciiééttéé>>..<<NNoommLLooggiicciieell>>

Comme par exemple : rraattpp..mmééttrrooppoolliittaaiinn..ppeerrssoonnnneell ou

rraattpp..mmééttrrooppoolliittaaiinn..mmaattéérriieell

123

Page 124: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Annexe 2 : Caractères d'échappement Voici les séquences d'échappement que nous pouvons utiliser :

SSééqquueennccee dd''éécchhaappppeemmeenntt CCaarraaccttèèrree oobbtteennuu \\'' SSiimmppllee gguuiilllleemmeett \\"" DDoouubbllee gguuiilllleemmeett \\\\ AAnnttiiSSllaasshh \\00 NNuullll \\aa AAlleerrttee ((bbiipp)) \\bb RReettoouurr AArrrriièèrree \\ff NNoouuvveellllee ppaaggee \\nn RReettoouurr àà llaa lliiggnnee \\rr RReettoouurr cchhaarriioott \\tt TTaabbuullaattiioonn \\vv TTaabbuullaattiioonn vveerrttiiccaallee

124

Page 125: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

Annexe 3 – Noms et Mots-Clés Il est important que les noms de vos objets, méthodes, propriétés, etc.. n'entrent pas en conflit avec des mots-clés utilisés par le langage pour signifier quelque chose. Si vous essayez de nommer un élément avec un mot qui s'avère être un mot-clé, vous obtiendrez une erreur de syntaxe car le compilateur supposera que le nom est une instruction. De plus, comme le Framework .NET permet l'interopérabilité entre langages, il est également important de ne pas utiliser des mots-clés qui seraient des mots-clés dans d'autres langages .NET.

1. Liste des mots-clés Visual Basic .NET Voici donc un tableau indiquant la liste des mots-clés utilisés en Visual Basic .NET et dont vous ne pourrez pas vous servir pour nommer des éléments de code en langage C#. Abs Do Loc RGB Add Double Local Right AddHandler Each Lock RmDir AddressOf Else LOF Rnd Alias ElseIf Log RTrim And Empty Long SaveSettings Ansi End Loop Second AppActivate Enum LTrim Seek Append EOF Me Select As Erase Mid SetAttr Assembly Error MIRR Shared Atan Event MkDir Shell Auto Exit Module Short Beep Exp Month Sign Binary Explicit MustInherit Sin BitAnd ExternalSource MustOverrride Single BitNot False MyBase SLN BitOr FileAttr MyClass Space BitXor FileCopy Namespace Spc Boolean FileDateTime New Split ByRef FileLen Next Sqrt Byte Filter Not Static ByVal Finally Nothing Step Call Fix NotInheritable Stop Case For NotOverridable Str Catch Format Now StrComp Cbool FreeFile Nper StrConv Cbyte Friend NPV Strict Cdate Function Null String CDbl FV Object Structure Cdec Get Oct Sub

125

Page 126: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

ChDir GetAllSettings Off Switch ChDrive GetAttr On SYD Choose GetException Open SyncLock Chr GetObject Option Tab Cint GetSettings Optional Tan Class GetType Or Text Clear Goto Overloads Then CLng Handles Overridable Throw Close Hex Overrides TimeOfDay Collection Hour ParramArray Timer Command If Pmt TimeSerial Compare IIf PPmt TimeValue Const Implements Preserve To Cos Imports Print Today CreateObject In Private Trim Cshort Inherits Property Try Csng Input Public TypeName CStr InStr Put TypeOf CurDir Int PV Ubound Date Integer QBColor Ucase DateAdd Interface Raise Unicode DateDiff Ipmt RaiseEvent Unlock DatePart IRR Randomize Until DateSerial Is Rate Val DateValue IsArray Read WeekDay Day IsDate ReadOnly While DDB IsDbNull ReDim Width Decimal IsNumeric Remove With Declare Item RemoveHandler WithEvents Default Kill Rename Write Delegate LCase Replace WriteOnly DeleteSettings Left Reset Xor Dim Lib Resume Year Dir Line Return

126

Page 127: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

2. Liste des mots-clés C# Comme vous allez pouvoir le constater, le langage C# comprend beaucoup moins de mots-clés que le langage Visual Basic .NET. Comme pour les mots-clés VB, tous les termes dans le tableau ci-dessous sont des mots-clés qu'il n'est pas possible d'utiliser comme identifiant en C#. abstract do implicit params switch

as double in private this

base else int protected throw

bool enum interface public true

break event internal readonly try

byte explicit is ref typeof

case extern lock return uint

catch false long sbyte ulong

char finally namespace sealed unchecked

checked fixed new short unsafe

class float null sizeof ushort

const for object stackalloc using

continue foreach operator static virtual

decimal goto out string volatile

default if override struct void

delegate while

127

Page 128: Langage C# - Les Bases - 3kernels.free.fr3kernels.free.fr/divers/support/insta/c-sharp/csharp.pdf · Chapitre 1 : Visual Studio .NET 1. Introduction Visual Studio .Net est l’environnement

128