Vous êtes sur la page 1sur 248

Cours CSharp

1
Première partie.

Notions de base
Qu’est-ce que C# ?

 C# est un langage de programmation orienté objet et à base de


composants, simple et moderne, qui ressemble à C++ et à Java.

 C# est présenté comme le langage de base de la stratégie .NET de


Microsoft.

 Il est inclus dans l’environnement de développement intégré Visual


Studio .NET de même que Visual Basic .NET, Visual C++.Net , Visual J#
et JScript.

 Tous ces langages permettent l’accès à l'ensemble des composants de


l'architecture .NET, dont le moteur d’exécution appelé le CLR (Common
Language Runtime) et une bibliothèque complète de classes.

3
C# & le Framework .Net

C# est le langage principal de .NET Framework et son utilisation


comporte les avantages suivants:

 Les types de données de C# correspondent exactement au CLR


(Common Language Runtime) sans couche intermédiaire et C# peut
présenter ainsi un petit avantage de performance;

 Dans la documentation Microsoft, beaucoup d'exemples sont donnés en


C# uniquement ;

 C# a une syntaxe plus stricte et plus sûre, et exclut l’utilisation de


typage implicite ;

 C# a des fonctions de documentation de type XML intégrées dans le


langage ;

 C# a une syntaxe plus familière pour les programmeurs C, C++, Java


et Perl.

4
L’environnement Visual Studio .Net

Visual Studio .Net est un environnement de


développement intégré (IDE) riche en outils contenant
toutes les fonctionnalités nécessaires à la création de
projets C#, VB.Net, C++.Net, J#, JScript.

5
L’environnement Visual Studio .Net

Installation:
Si vous n’avez pas encore installé Visual Studio,
accédez à la page Téléchargements Visual Studio pour
l’installer gratuitement.

6
C# & le Framework .Net

Créer un nouveau projet

7
C# & le Framework .Net
C# & le Framework .Net
C# & le Framework .Net
C# & le Framework .Net
Première application C#

using System;
namespace Test
{ /// <summary>
/// Summary description for Program
/// </summary>
class Program
{ /// <summary>
/// The main entry point for the application.
/// </summary>
public static void Main(string[] args)
{
Console.WriteLine(" Bonjour !");
}
}
}

12
L’explorateur de solutions

L’explorateur de solution est


une fenêtre qui montre les
fichiers qui composent la
solution sous forme d’une
arborescence.

13
Fichiers de la solution 1

Test.sln
 C’est le fichier le plus haut de la solution. Il y en a un par application.

 Tout fichier de solution contient un ou plusieurs fichiers de projet.

 Dans le système de fichiers, tout fichier de solution porte l’extension .sln.

 Dans l’explorateur de solutions, il apparaît avec un nom plus facile à lire,


comme « Solution ‘Test’ » dans ce projet.

14
Fichiers de la solution 2

Test.csproj
 C’est un fichier de projet C#.

 Tout fichier de projet contient un ou plusieurs fichiers source.

 Les fichiers source d’un même projet doivent être rédigés dans le même
langage de programmation.

 Ce type de fichier s’affiche dans l’explorateur de solutions uniquement à


l’aide du nom du projet, mais est stocké dans le système de fichiers avec
l’extension .csproj.

15
Fichiers de la solution 3

Program.cs
 C’est un fichier source C#, dans lequel vous allez rédiger votre code.

 Il contient un peu de code généré automatiquement par Visual Studio.Net


et qu’on va examiner sous peu.

16
Fichiers de la solution 4

AssemblyInfo.cs
 C’est un autre fichier source C#.

 Ce fichier permet d’ajouter des attributs à votre programme, comme le


nom de l’auteur, la date de rédaction du programme, etc.

 Il existe d’autres attributs plus avancés permettant d’agir sur la façon


dont s’exécute le programme.

17
Fichiers de la solution 5

App.ico
 C’est l’icône associé à l’application.

 Toutes les applications Windows possédant une interface utilisateur


disposent d’une icône affichée sous forme réduite dans la barre des tâches
lorsque l’application s’exécute.

18
Les espaces de noms

 Une ressource dans le code source a la possibilité d’être déclarée et définie


à l’intérieur d’un espace de noms.

 Si une ressource n’est déclarée dans aucun espace de noms elle fait partie
d’un espace de noms global et anonyme.

using Toto1;
using Toto1.Toto2;
using System;
namespace Toto1
{
// ici les ressources de l'espace de noms Toto1
namespace Toto2
{
// ici les ressources de l'espace de noms Toto1.Toto2
}
// ici les ressources de l'espace de noms Toto1
}

19
Création d’une documentation à l’aide
XML et de commentaires
 Dans Visual C#, il est possible de créer la documentation pour le code en
incluant des balises XML dans les champs de commentaires directement
avant le bloc de code auquel elles se réfèrent.

 Parmi les balises XML standard prises en charge par le compilateur C#, il
y a: <summary>, <remarks>, <returns>, <value>, <exception>, <param>,
<example>, <para>, <see>, <typeparam>, …..

 Exemple :
/// <summary>
/// The main entry point for the application.
/// </summary>

20
Création d’une documentation à l’aide
XML et de commentaires
<summary> : Ajoute des informations succinctes relatives à un type ou un
membre.
 Exemple : /// <summary>
/// The main Math class.
/// Contains all methods for performing
basic math functions.
/// </summary>
public class Math
{
// Adds two integers and returns the
result
/// <summary>
/// Adds two integers and returns the
result.
/// </summary>
public static int Add(int a, int b)
{
// If any parameter is equal to the
max value of an integer
// and the other is greater than
zero
if ((a == int.MaxValue && b > 0) ||
(b == int.MaxValue && a > 0))
throw new
System.OverflowException();

return a + b;
}
21
}
Création d’une documentation à l’aide
XML et de commentaires
<remarks> : Complète les informations relatives aux types ou aux membres
fournies par la balise <summary> .

 Exemple :
/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math
functions.
/// </summary>

/// <remarks>
/// This class can add, subtract, multiply and divide.
/// </remarks>

public class Math


{
}

22
Création d’une documentation à l’aide
XML et de commentaires
<returns> : Décrit la valeur de retour d’une déclaration de méthode.

 Exemple :
/// <summary>
/// Adds two integers and returns the result.
/// </summary>
/// <returns>
/// The sum of two integers.
/// </returns>
public static int Add(int a, int b)
{
// If any parameter is equal to the max value of an integer and
// the other is greater than zero
if ((a == int.MaxValue && b > 0) || (b == int.MaxValue && a > 0))
throw new System.OverflowException();

return a + b;
}

23
Création d’une documentation à l’aide
XML et de commentaires
<value> : La balise <value> est similaire à la balise <returns>, excepté que vous
l’utilisez pour les propriétés.

 Exemple :

/// <summary>
/// The main Math class.
/// Contains all methods for performing basic math functions.
/// </summary>
/// <remarks>
/// This class can add, subtract, multiply and divide.
/// These operations can be performed on both integers and doubles
/// </remarks>
public class Math
{
/// <value>Gets the value of PI.</value>
public static double PI { get; }
}

24
Création d’une documentation à l’aide
XML et de commentaires
<exception> : Informer qu’une méthode peut lever des exceptions spécifiques.

 Exemple :

public class Math


{
/// <summary>
/// Divides an integer by another and returns the result.
/// </summary>
/// <returns>
/// The division of two integers.
/// </returns>
/// <exception cref="System.DivideByZeroException">Thrown when a division
/// by zero occurs.</exception>
public static int Divide(int a, int b)
{
return a / b;
}
}

25
Création d’une documentation à l’aide
XML et de commentaires
<param> : Décrire les paramètres d’une méthode.

 Exemple :
/// <summary>
/// Adds two doubles and returns the result.
/// </summary>
/// <returns>
/// The sum of two doubles.
/// </returns>
/// <exception cref="System.OverflowException">Thrown when one parameter is
/// max and the other is greater than zero.</exception>
/// <param name="a">A double precision number.</param>
/// <param name="b">A double precision number.</param>
public static double Add(double a, double b)
{
if ((a == double.MaxValue && b > 0) || (b == double.MaxValue && a > 0))
throw new System.OverflowException();

return a + b;
}

26
Création d’une documentation à l’aide
XML et de commentaires

 Une fois le code documenté, il


est possible de générer des
pages Web de commentaires à
partir de Visual studio comme
suit: Il suffit d’aller dans le
menu Outils et de cliquer sur
Générer les pages Web de
commentaires.

27
Les commentaires

Il existe trois façons de commenter du texte dans un fichier


source C# :

 Le texte placé entre les balises /* suivie de */ est commenté. Ces balises
peuvent éventuellement se trouver sur deux lignes différentes.

 Si une ligne contient la balise // alors le texte de cette ligne qui suit cette
balise est commenté.

 Si une ligne contient la balise /// alors le texte de cette ligne qui suit cette
balise est commenté. De plus ce texte fera partie de la documentation
automatique.

28
Votre premier programme

using System;
namespace HelloWorld
{
Class Hello
{
static void Main ()
{
System.Console.WriteLine(" Hello World! ");
// Garder la console window ouverte en mode débogage.
System.Console.WriteLine(" Appuyez sur une touche pour
sortir. " );
System.Console.ReadKey();
}
}
} 29
Les Entrées/ Sorties

 La classe Console fournit une application C# avec accès à l’entrée


standard, à la sortie standard et aux flux d’erreur satandards.

 Les méthodes Console.Write et Console.WriteLine affichent des


informations sur l’écran de la console.

 Les méthodes Console.Read et Console.ReadLine lisent l’entrée de


l’utilisateur sur le clavier.

 Appeler ReadKey à la fin de la méthode Main empêche que la fenêtre


de console ne se ferme avant que vous ayez pu lire la sortie lorsque vous
lancez le mode débogage en appuyant sur F5.

30
La méthode Main() (1/3)

 Chaque assemblage exécutable a au moins une méthode statique Main()


dans une de ses classes.

 Cette méthode représente le point d’entrée du programme, c’est-à-dire


que le thread principal créé automatiquement lors du lancement du
processus va commencer par exécuter le code de cette méthode.

 Il peut y avoir éventuellement plusieurs méthodes Main() (chacune


dans une classe différente) par programme. Le cas échéant, il faut
préciser au compilateur quelle méthode Main() constitue le point
d’entrée du programme.

31
La méthode Main() (2/3)
 Déclarez la méthode Main d'une des manières suivantes :
 Elle peut retourner void : static void Main()
{
//…
}

 Elle peut également retourner int : static int Main()


{
//…
return 0;
}

 Avec les deux types de retour, elle peut accepter des arguments :
Le paramètre de la méthode Main est un tableau static void Main(string[] args)
string qui représente les arguments de la ligne de {
commande utilisés pour appeler le programme. // ...
}
static int Main(string[] args)
{
// …
}
32
La méthode Main() (3/3)

 Le programme suivant ajoute les nombres passés en arguments en ligne de


commande, et affiche le résultat. S’il n’y a pas d’argument, le programme le
signale :

using System;
class Prog
{ static void Main(string[] args)
{ if (args.Length == 0)
Console.WriteLine("Entrez des nombres à ajouter.");
else { long result = 0;
foreach( string s in args )
result += Int64.Parse(s);
// la méthode Parse Convertit une chaîne de caractère
// en un entier 64-bit signé équivalent.
Console.WriteLine("Somme de ces nombres :{0}",result);
}
}
}
33
Types de données C# prédéfinis (1/2)
Il existe 6 catégories de types prédéfinis C#:

 Référence: object, string

 Signé: sbyte, short, int, long

 Non signé: byte, ushort, uint, ulong

 Caractère : char

 Point flottant : float, double, decimal

 Logique : bool

34
Types de données C# prédéfinis (2/2)

 Les types prédéfinis sont des alias des types CTS définis dans le
framework .Net.

 Exemple:
Le type int est un alias de System.Int32
 Int32 est une structure qui appartient à l’espace de nom System

35
Types de données C# prédéfinis
Types entiers:

36
Types de données C# prédéfinis
Types de données:

37
Types de données C# prédéfinis
Caractères d'échappement

38
Variables & Types de Données

 Déclaration de Variables :
Étape 1 : Déterminer le Type de données à utiliser.
Étape 2 : Créer le nom de la Variable.
Étape 3 : Terminer par un point-virgule.
Exemple : int compteur; double taux;
 Initialisation de Variables :
Étape 1 : Utiliser l’opérateur de l’affectation.
Étape 2 : Déterminer la valeur à assigner.
Étape 3 : Terminer par un point-virgule.
Exemple : int compteur = 10; double taux = 150.59;

39
Chaînes de caractères
 Une chaîne de caractères peut être déclarée et initialisée de plusieurs
façons:
string s = "Hello World " ;
Résultat : Hello World
string s = "\"Hello\"";
Résultat : "Hello"
 string s = "Hello\nWorld";
Résultat : Hello
World
 string s = @"C:\Test\SubDirectory";
Résultat : C:\Test\SubDirectory

L’arobase @ devant une chaine a pour effet d’annuler l’interprétation de


l’antislash (\)

40
Constantes

 Les constantes en C# se déclare avec le mot clé const

 Exemple :
const int MAX_EMPLOYES = 3000;
const string SQL_CONNECTION_STRING =
“database=Northwind;user_id =moi; password = secret”;

41
Les conversions entre nombres et chaînes
de caractères

 nombre -> chaîne :


"" + nombre
 chaine -> int :
int.Parse(chaine) ou Int32.Parse(chaine)
 chaîne -> long :
long.Parse(chaine) ou Int64.Parse(chaine)
 chaîne -> double :
double.Parse(chaîne) ou Double.Parse(chaîne)
 chaîne -> float :
float.Parse(chaîne) ou Float.Parse(chaîne)

42
Erreurs de conversions
 La conversion d'une chaîne vers un nombre peut échouer si la chaîne ne
représente pas un nombre valide. Il y a alors génération d'une erreur
fatale.

 Cette erreur est appelée exception en C#.

43
Les changements de type

 Il est possible, dans une expression, de changer momentanément le codage


d'une valeur.

 On appelle cela changer le type d'une donnée ou en anglais type casting.

 La syntaxe du changement du type d'une valeur dans une expression est la


suivante: (type) valeur

 La valeur prend alors le type indiqué. Cela entraîne un changement de


codage de la valeur.

44
Les changements de type

 Exemple:
int i, j;
float isurj;
isurj= (float)i/j; // priorité de () sur /
 Ici il est nécessaire de changer le type de i ou j en réel sinon la division
donnera le quotient entier et non réel.

 i est une valeur codée de façon exacte sur 2 octets

 (float) i est la même valeur codée de façon approchée en réel sur 4 octets

 Il y a donc transcodage de la valeur de i. Ce transcodage n'a lieu que le


temps d'un calcul, la variable i conservant toujours son type int.

45
Les tableaux, Les énumérations, et les
structures

 Pour grouper des variables ou des valeurs, on peut utiliser les trois outils
suivants:

 Les tableaux

 Les énumérations.

 Les structures.

46
Les tableaux de données
 Un tableau ou Array C# est un objet permettant de rassembler sous un
même identificateur des données de même type.

 Sa déclaration est la suivante :


Type[] Tableau=new Type[n]
n est le nombre de données que peut contenir le tableau.
 La syntaxe Tableau[i] désigne la donnée n°i où i appartient à l'intervalle
[0,n-1].

 Toute référence à la donnée Tableau[i] où i n'appartient pas à l'intervalle


[0,n-1] provoquera une exception.

 Un tableau peut être initialisé en même temps que déclaré : int[]


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

47
Les tableaux de données
 Les tableaux ont une propriété Length qui est le nombre d'éléments du
tableau.

 Un tableau à deux dimensions pourra être déclaré comme suit : Type[,]


Tableau=new Type[n,m];

 où n est le nombre de lignes, m le nombre de colonnes.

 La syntaxe Tableau[i,j] désigne l'élément j de la ligne i de Tableau.

 Le tableau à deux dimensions peut lui aussi être initialisé en même


temps qu'il est déclaré :
double[,] réels=new double[,] { {0.5, 1.7}, {8.4, -6}};

48
Les tableaux de données
 Le nombre d'éléments dans chacune des dimensions peut être obtenue
par la méthode GetLength(i) où i=0 représente la dimension
correspondant au 1er indice, i=1 la dimension correspondant au 2ième
indice, …

 Un tableau de tableaux est déclaré comme suit :


Type[][] Tableau=new Type[n][];
 La déclaration ci-dessus crée un tableau de n lignes.

 Chaque élément Tableau[i] est une référence de tableau à une dimension.

 Ces tableaux ne sont pas créés lors de la déclaration ci-dessus.

49
Exemple 1
//un tableau de tableaux
string [][] noms= new string[3][];
for (int i = 0; i < noms.Length; i++)
{
noms[i] = new string[i + 1];
}
//Initialisation
for(int i=0;i<noms.Length;i++){
for(int j=0;j<noms[i].Length;j++){
noms[i][j]=""+i+j ;
}
}

Ici noms[i] est un tableau de i+1 elements


Comme noms[i] est un tableau, noms[i].Length est son nombre d’élements

50
Exemple 2 (1/4)
using System;
// classe de test
public class test {
public static void Main(){
// un tableau à 1 dimension initialisé
int[] entiers=new int[] {0,10,20,30};
for (int i=0;i<entiers.Length;i++)
{
Console.WriteLine("entiers["+i+"]="+entiers[i]);
}

51
Exemple 2 (2/4)
// un tableau à 2 dimensions initialisé
double[,] reels=new double[,] { {0.5, 1.7}, {8.4, -6}};
for (int i=0;i<reels.GetLength(0);i++)
{
for (int j=0;j<reels.GetLength(1);j++)
{
Console. WriteLine("reels["+i+","+j+"]="+reels[i,j]);
}//for j
}//for i

52
Exemple 2 (3/4)
// un tableau de tableaux
string[][] noms=new string[3][];
for (int i=0;i<noms.Length;i++)
{ noms[i]=new string[i+1];
}//for
// initialisation
for (int i=0;i<noms.Length;i++)
{ for(int j=0;j<noms[i].Length;j++)
{ noms[i][j]="nom"+i+j;
}//for j
}//for i

53
Exemple 2 (4/4)
// affichage
for (int i=0;i<noms.Length;i++)
{
for(int j=0;j<noms[i].Length;j++)
{
Console.Out.WriteLine("noms["+i+"]["+j+"]="+noms[i][j]);
}//for j
}//for i
}//Main
}//class

54
Exécution de l’exemple

entiers[0]=0
entiers[1]=10
entiers[2]=20
entiers[3]=30
reels[0,0]=0.5
reels[0,1]=1.7
reels[1,0]=8.4
reels[1,1]=-6
noms[0][0]=nom00
noms[1][0]=nom10
noms[1][1]=nom11
noms[2][0]=nom20
noms[2][1]=nom21
noms[2][2]=nom22

55
Les énumérations

 Une énumération est un type de données dont le domaine de valeurs est


un ensemble de constantes entières.

 Considérons un programme qui a à gérer des mentions à un examen.


Il y en aurait cinq : Passable, AssezBien, Bien, TrèsBien, Excellent.
On pourrait alors définir une énumération pour ces cinq constantes :
enum Mentions { Passable, AssezBien, Bien, TrèsBien, Excellent };

56
Les énumérations

 De façon interne, ces cinq constantes sont codées par des entiers
consécutifs commençant par 0 pour la première constante, 1 pour la
suivante, etc...

 Une variable peut être déclarée comme prenant ces valeurs dans
l'énumération :

 Exemples :
1. Mentions maMention = Mentions.Passable;
2. if (maMention == Mentions.Passable) { Console.WriteLine("Peut
mieux faire");}

57
Les énumérations

 On peut obtenir toutes les valeurs de l'énumération :


// liste des mentions sous forme de chaînes
foreach (Mentions m in Enum.GetValues(maMention.GetType())) {
Console.WriteLine(m);
}

 On peut également obtenir la liste des valeurs de l’énumérations sous


forme d’entiers:

//liste des mentions sous forme d'entiers


foreach (int m in Enum.GetValues(typeof(Mentions))) {
Console.WriteLine(m);
}

58
Les structures

 Struct (structure) est un type de valeur particulier, il crée une variable


pour stocker des multiples valeurs .

 Les structures sont définies à l'aide du mot clé struct .

 Exemple:
public struct Employee
{

public string empNumber;


public string empName;
public string position;
}

59
Les structures

Les structure partagent presque tous la même syntaxe que les classes, bien
qu'ils soient plus limités que ces dernières :

 Dans une déclaration de structure, les champs ne peuvent pas être


initialisés à moins qu'ils ne soient déclarés comme const ou static.

 Une structure ne peut pas déclarer de constructeur par défaut (un


constructeur sans paramètres) ni de destructeur.

 Les structures sont copiées lors de l'assignation. Lorsqu'une structure est


assignée à une nouvelle variable, toutes les données sont copiées et les
modifications apportées à la nouvelle copie ne changent pas les données
de la copie d'origine.

Les structures sont des types valeur et les classes des types référence.

60
Les structures
 Contrairement aux classes, les objets de type struct peuvent être
instanciés sans recours à l'opérateur new.

 Les structures peuvent déclarer des constructeurs qui ont des


paramètres.

 Une structure ne peut pas hériter d'un autre structure ou d'une


classe ; il ne peut pas non plus servir de base à une classe. Tous les
structures héritent directement de System.ValueType, qui hérite de
System.Object.

 Une structure peut implémenter des interfaces.

 Une structure peut être utilisé comme un type Nullable et peut se voir
assigner une valeur Null.
61
Les structures
 Exemple
public struct CoOrds
{
public int x, y; Résultat de l’exemple
public CoOrds(int p1, int p2)
{
x = p1; CoOrds 1 : x= 0, y=0
y = p2;
} CoOrds 2 : x=10, y=10
}
// Usage of struct objects.
class TestCoOrds
{
static void Main()
{
// Initialize:
CoOrds coords1 = new CoOrds();
CoOrds coords2 = new CoOrds(10, 10);
// Display results:
Console.Write("CoOrds 1: ");
Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
Console.Write("CoOrds 2: ");
Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y);
// Keep the console window open in debug mode. Console.WriteLine("Press
any key to exit.");
Console.ReadKey();
}
}
62
Les structures
 Cet exemple montre une caractéristique propre aux structures. Il crée
un objet CoOrds sans utiliser l'opérateur new.
 Si vous remplacez le mot struct par le mot class, le programme ne peut
pas se compiler.
// Declare a struct object without « new »
class TestCoOrdsNoNew
{
Résultat de l’exemple
static void Main()
{
// Declare an object: CoOrds 1 : x= 10, y=20
CoOrds coords1;
// Initialize:
coords1.x = 10;
coords1.y = 20;
// Display results:
Console.Write("CoOrds 1: ");
Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}

63
Les opérateurs
 Opérateur d’affectation:
Forme générale : V1=V2=....=Vn=expression
 Expression arithmétique
Les opérateurs des expressions arithmétiques sont les suivants :
+ addition
- soustraction
* multiplication
/ division : le résultat est le quotient exact si l'un au moins des
opérandes est réel. Si les deux opérandes sont entiers le résultat
est le quotient entier. Ainsi 5/2 -> 2 et 5.0/2 ->2.5.
% division : le résultat est le reste quelque soit la nature des
opérandes, le quotient étant lui entier. C'est donc l'opération
modulo.

64
Exemple
class Binary
{
public static void Main()
{
int x, y, result;
float floatResult;
x = 7; y = 5;
Exécution de l’exemple
result = x + y; x+y: 12
Console.WriteLine("x+y:{0}", result); x-y: 2
result = x - y; x*y: 35
Console.WriteLine("x-y:{0}", result);
result = x * y; x/y: 1
Console.WriteLine("x*y:{0}", result); x/y: 1.4
result = x / y; x%y: 2
Console.WriteLine("x/y:{0}", result);
floatresult = (float)x / (float)y;
result+=x: 9
Console.WriteLine("x/y:{0}", floatresult);
result = x % y;
Console.WriteLine("x%y:{0}", result);
result += x;
Console.WriteLine("result+=x:{0}", result);
}
}

65
Les opérateurs

Il existe diverses fonctions mathématiques. En voici quelques-unes :

 double Sqrt(double x) : racine carrée

 double Cos(double x) : Cosinus

 double Sin(double x) : Sinus

 double Tan(double x) : Tangente

 double Pow(double x,double y) : x à la puissance y (x>0)

 double Exp(double x) : Exponentielle

 double Log(double x) :Logarithme népérien

 double Abs(double x) : valeur absolue

66
Les opérateurs
 Toutes ces fonctions sont définies dans une classe C# appelée Math.

 Lorsqu'on les utilise, il faut les préfixer avec le nom de la classe où elles
sont définies.

 Ainsi on écrira :
double x, y=4;
x=Math.Sqrt(y);

67
Les opérateurs
 Priorités dans l'évaluation des expressions arithmétiques :
La priorité des opérateurs lors de l'évaluation d'une expression
arithmétique est la suivante (du plus prioritaire au moins prioritaire) :
[fonctions], [ ( )],[ *, /, %], [+, -]
Remarque :
Les opérateurs d'un même bloc [ ] ont même priorité.

68
Les opérateurs

 Opérateurs relationnels:
<, <=, ==, !=, >, >=
 Priorités:
1. >, >=, <, <=
2. ==, !=

 Le résultat d'une expression relationnelle est le booléen false si


expression fausse true sinon.

 Exemple :
boolean fin;
int x=1;
fin=x>4;

69
Les opérateurs
 Comparaison de deux caractères:
Il est possible de comparer deux caractères avec les opérateurs
relationnels.
Ce sont alors leurs codes ASCII, qui sont des nombres, qui sont alors
comparés.
 On rappelle que selon l'ordre ASCII on a les relations suivantes :
espace < .. < '0' < '1' < .. < '9' < .. < 'A' < 'B' < .. < 'Z' < .. < 'a' < 'b' <
.. <'z'

70
Les opérateurs
 Opérateurs booléens:
NOT ( ! )
AND ( && )
OR ( || )
 Exemple:
bool fin;
int x;
fin= x>2 && x<4;
 Les opérateurs relationnels ont priorité sur les opérateurs && et ||.

71
Les opérateurs
 Opérateurs de traitement de bits:

 Soient i et j deux entiers.


i<<n décale i de n bits sur la gauche. Les bits entrants sont des
zéros.
i>>n décale i de n bits sur la droite. Si i est un entier signé (signed
char, int, long) le bit de signe est préservé.
i & j fait le ET logique de i et j bit à bit.
i | j fait le OU logique de i et j bit à bit.
~i complémente i à 1
i^j fait le OU EXCLUSIF de i et j

72
Les opérateurs
 Combinaison d'opérateurs:
a=a+b peut s'écrire a+=b
a=a-b peut s'écrire a-=b
 Opérateurs d'incrémentation et de décrémentation:
La notation variable++ signifie
variable=variable+1 ou encore variable+=1
La notation variable-- signifie
variable=variable-1 ou encore variable-=1.

73
Les opérateurs
 L'opérateur ternaire « ? »
L'expression expr_cond ? expr1:expr2 est évaluée de la façon
suivante :
1. l'expression expr_cond est évaluée. C'est une expression
conditionnelle à valeur vrai ou faux
2. Si elle est vraie, la valeur de l'expression est celle de expr1. expr2
n'est pas évaluée.
3. Si elle est fausse, c'est l'inverse qui se produit :
la valeur de l'expression est celle de expr2. expr1
n'est pas évaluée.

74
Les opérateurs
 Exemple:
L'opération i=(j>4 ? j+1:j-1); affectera à la variable i : j+1 si j>4, j-1
sinon.
C'est la même chose que d'écrire if(j>4) i=j+1;
else i=j-1;mais c'est plus concis.

75
Structures de contrôle

 Une structure de contrôle est un élément du programme qui change le


comportement par défaut de l’unité d’exécution (du thread).

 Rappelons que ce comportement par défaut est d’exécuter les


instructions les unes à la suite des autres.

76
Structures de contrôle

 Les conditions:
Il existe trois types de conditions:
if/else
switch
L’opérateur ternaire ?:

77
Exemple

if( b == true ) // si b vaut true alors...


if( i >= 4 && i<= 6) // si i dans l'intervalle fermé [4,6] alors...
if( i < 4 || i > 6) // si i hors de l'intervalle fermé [4,6] alors...
...
// s="bonjour" si i strictement inférieur à j, sinon s="hello"
string s = i<j ? "bonjour" : "hello";
...
switch(i)
{
case 1: Console.WriteLine("i vaut 1");
break;
case 6: Console.WriteLine("i vaut 6");
break;
default:Console.WriteLine("i ne vaut ni 1 ni 6");
break;
}

78
Structures de contrôle

 Les boucles
Il existe quatre types de boucles:
while
do/while
for
foreach

79
Exemple

80
Passage de paramètres à une fonction
 Les paramètres déclarés dans la signature d’une fonction sont appelés
paramètres formels.

 Lorsqu’on appelle une fonction, on lui passe des variables qui vont être
recopiés dans les paramètres formels pour effectuer le calcul. Ces
variables sont appelés paramètres effectifs.

 Nous nous intéressons à la façon dont un paramètre formel récupère la


valeur d'un paramètre effectif.

81
Passage par valeur

 La valeur du paramètre effectif est recopiée dans le paramètre formel


correspondant.

 On a deux entités distinctes.

 Si la fonction modifie le paramètre formel, le paramètre effectif n'est lui


en rien modifié.

82
Exemple

static void permutation( int a,int b)


{ Résultat de l’exemple
int t;
t = a; Avant permutation a= 10, b=20
a = b; Après permutation a=10, b=20
b = t;
}
static void Main(string[] args)
{
int a, b;
a = 10; b = 20;
Console.WriteLine(" Avant permutation a= {0}, b={1}", a, b);
permutation(a, b);
Console.WriteLine(" Apres permutation a= {0}, b={1}", a, b);
Console.ReadKey();
}

83
Passage par référence

 Dans un passage par référence, le paramètre effectif et le paramètre formel


sont une seule et même entité.

 Si la fonction modifie le paramètre formel, le paramètre effectif est lui


aussi modifié. En C#, ils doivent être tous deux précédés du mot clé ref.

84
Exemple

static void permutation( ref int a,ref int b)


{
int t; Résultat de l’exemple
t = a;
a = b; Avant permutation a= 10, b=20
b = t; Après permutation a=20, b=10
}
static void Main(string[] args)
{
int a, b;
a = 10; b = 20;
Console.WriteLine(" Avant permutation a= {0}, b={1}", a, b);
permutation(ref a, ref b);
Console.WriteLine(" Apres permutation a= {0}, b={1}", a, b);
Console.ReadKey();
}

85
Passage par référence avec le mot clé out

Considérons l'exemple suivant dans lequel la variable x ne serait pas


initialisée avant l'appel à la fonction changeInt :
Erreur de compilation
using System;
class Program{ Utilisation d’une variable locale
static void Main(string[] args) non assignée ‘x’
{
int x;
changeInt(ref x);
Console.Out.WriteLine("Paramètre effectif x=" + x);
}
private static void changeInt(ref int a)
{
a = 30;
Console.WriteLine("Paramètre formel a=" + a);
}

86
Passage par référence avec le mot clé out

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


 Utilisation d’une variable locale non assignée ‘x’

 On peut contourner l'obstacle soit en affectant une valeur initiale à x.


 Ou bien on peut remplacer le mot clé ref par le mot clé out.
 On exprime alors que le paramètre ‘x’ est uniquement un paramètre de
sortie et on a donc pas besoin de valeur initiale.

87
Exemple
Résultat de l’exemple

using System; Paramètre formel a= 30


class Program{
static void Main(string[] args) Paramètre effectif x=30
{
int x;
changeInt(out x);
Console.Out.WriteLine("Paramètre effectif x=" + x);
}
private static void changeInt(out int a)
{
a = 30;
Console.WriteLine("Paramètre formel a=" + a);
}

88
Deuxieme partie.

C#: LANGUAGE OBJET


Classe && Objet

La classe joue le rôle de moule permettant


de reproduire autant d’objets (instance) que
l ’application le demande.
Classe && Objet

 Classe = patron/moule (= type)

 Une classe est la description d'une collection objets homogènes (mêmes


caractéristiques et même comportements).
 Décrit la structure de l'état (les attributs et leurs types)
 Instance : Objet obéissant à un patron
 Un objet est une instance de classe.
 Par analogie, on peut aussi considérer une classe comme le type d'une
variable, et l'objet comme la valeur de cette même variable.
 Classe : abstrait
 La notion/ le type "chien "
 Instance : concret
 “Ce chien noir que je vois dans la rue”, “Le chien de mon voisin”
Les membres de classe
 Les membres d'une classe peuvent être des:
- Données (champs)
- Méthodes (fonctions)
- Propriétés
- Indexeurs
- Délégués
- Evénements

 Ces membres peuvent être accompagnés de l'un des cinq mots clés suivants :
- private n'est accessible que par les seules méthodes internes de la classe.
- public est accessible par toute fonction définie ou non au sein de la classe.
- protected n'est accessible que par les seules méthodes internes de la classe ou d'un type
dérivé de cette classe (voir ultérieurement le concept d'héritage).
- internal est accessible depuis l'assembly en cours uniquement.
- protected internal est accessible depuis l'assembly en cours ou depuis des types
dérivés de cette classe.

 En général, les données d'une classe sont déclarées privées alors que ses
méthodes et propriétés sont déclarées publiques.
Les membres statiques de classe

 L’utilisation d’attributs statiques permet de partager une même valeur d’un


attribut d’une classe avec tous les objets de cette classe.

 On utilise des méthodes statiques, appelées directement sur la classe, pour modifier
les attributs statiques.

 Exemple :
public class UnExemple {
int numero; // Défini pour chaque objet
static int numero_suivant; // Défini pour la classe
}
....
Console.WriteLine("N° suivant = " + UnExemple.numero_suivant );
// pour accéder à un membre static: NomDeLaClasse.MembreStatic
Console.WriteLine("N° = " + UnExemple.numero );
// Erreur de compilation, car la variable n'est pas définie pour la
classe
UnExemple InstanceDUnExemple = new UnExemple();
Console.WriteLine("N° = " + InstanceDUnExemple.numero_suivant);
Les classes statiques

 Une classe statique ne contient que des membres statiques, et ne peut être
instanciée. Le mot clé static précède la déclaration de cette classe.

 Exemple :

public static class UneClasseStatique{


public static void Afficher(string message)
{
// ...
}
}
.....
UneClasseStatique.Afficher("Un exemple de message");
Les propriétés

L’expérience de la programmation nous as enseigné que pour chaque


attribut privé d’une classe il faut prévoir deux méthodes pour la lecture
et pour la modification de cet attribut.

On appelle ces méthodes des accesseurs/modifieurs ou getter/setter


methods.

Pour l’attribut prenom de la classe personne par exemple il faut


prévoir les méthodes:

public String getPrenom()


{
return prenom;
}
public void setPrenom(String P)
{
this.prenom=P;
}

95
Les propriétés

 Les propriétés permettent d’éviter la lourdeur de ces méthodes


accesseurs/modifieurs.

 Elles permettent de manipuler des attributs privés comme s'ils étaient


publics.

 Leurs forme est comme suit:

public Type propriété{

get {...}

set {...}

96
Les propriétés

 Ainsi pour l’attribut « prenom » de la classe Personne on déclare ses


propriétés comme suit:
public string Prenom
{
get { return prenom; }
set { prenom = value; }

 Ainsi p.Prenom="ali" est équivalent à l’appel de la méthode


setPrenom("ali") par exemple.
 Il faut cependant remarquer que Prenom#prenom (ils n’ont pas le
même nom)

97
Les indexeurs

 Un indexeur est une propriété spéciale qui permet d’utiliser une


instance de la classe comme un tableau, en utilisant les crochets.
 La déclaration d’un indexeur est de la forme suivante :

Type_élément this[ Type_index index ]


{
get // élément [index] lu
{
Code retournant une valeur du Type_éléments spécifié
dont l'index est dans le paramètre index
}
set // élément [index] modifié
{
Code utilisant le paramètre prédéfini "value"
pour le stocker à l'index spécifié par le paramètre index
}
}

98
Les indexeurs

Type_élément this[ Type_index index ]


{
get // élément [index] lu
{
Code retournant une valeur du Type_éléments spécifié
dont l'index est dans le paramètre index
}
set // élément [index] modifié
{
Code utilisant le paramètre prédéfini "value"
pour le stocker à l'index spécifié par le paramètre index
}
}

 Type_élément : Type de chaque élément du tableau virtuel.


 Type_index: Type de l'indice spécifié entre crochets.
 Index : Variable contenant la valeur de l'indice de l'élément lu ou modifié.

 L'index peut avoir un autre type que int. C'est le cas des tables de hashage de
l'espace de nom System.Collections.
99
Les indexeurs

 Exemple :
Déclaration :

class clA {

private int [ ] champ = new int [10];

public int this [int index]{


get { return champ[ index ] ; }
set { champ[ index ] = value ; }
}
}

Utilisation :

clA Obj = new clA( );


for ( int i =0; i<5; i++ )
Obj[ i ] = i ;
int x = Obj[ 2 ] ; // x = 2
int y = Obj[ 3 ] ; // y = 3
100
Les délégués

 Un délégué est un objet qui fait référence à une méthode ou

simplement, c’est une variable de type référence pouvant contenir

une référence de méthode. Les délégués en C# sont comme les

pointeurs de fonction en C et C++, sauf qu’ils sont de type

sécurisé. Il fournit un moyen d’indiquer quelle méthode doit être

appelée lorsqu’un événement est déclenché.

101
Les délégués

 Les délégués ont les caractéristiques suivantes:

 Les délégués héritent de la classe System.MulticastDelegate.

 Ils ont une signature et un type de retour. Une fonction


ajoutée aux délégués doit être compatible avec cette
signature.

 Les délégués peuvent désigner des méthodes statiques ou


d’instance.

 Une fois qu’un objet délégué a été créé, il peut invoquer


dynamiquement les méthodes vers lesquelles il pointe au
moment de l’exécution.

102
Les délégués

 Les délégués sont utiles pour la gestion des événements. Ils sont déclarés
d’une manière similaire aux fonctions :
• Mot-clé : delegate
• Sans corps de fonction
• Un type de retour et une liste de paramètres

 On peut déclarer une variable avec le type délégué. Cette variable sera
initialisée comme une référence à toute fonction qui a le même type de
retour et la même liste de paramètres que le délégué.

 On peut alors appeler cette fonction en utilisant la variable de type


délégué comme s’il s’agit d’une fonction.

103
Les délégués

 Vous pouvez définir des types de délégués dans les classes,


directement dans les espaces de noms, ou même dans l'espace de
noms global. Cette dernière possibilité est déconseillée.

 Exemple :

public delegate int MyDelegate (string str);

 Ici le délégué peut être utilisé pour référencer toute méthode comportant
un seul paramètre de type string et renvoyant une variable de type int.

104
Les délégués

 Instanciation des délégués :

Une fois qu’un type de délégué est déclaré, un objet délégué doit être

créé avec le mot-clé « new » et doit être associé à une méthode

particulière. Lors de la création d’un délégué, l’argument transmis à

l’expression « new » est le nom de la méthode, mais sans les arguments.

105
Les délégués

 Exemple (1/3) :

using System;

namespace Test{

public class DelegateApp {


static int n = 4;

/* Déclarer le délégué. Ici, le type de retour et le type de


paramètre doivent être identique au type de retour et au type
de paramètre de la méthode "operation" qui sert du délégué.
*/
delegate int operation(int n);

106
Les délégués

 Exemple (2/3) :

public static int sum(int p) {


n += p;
return n;
}
public static int sub(int q) {
n -= q;
return n;
}
public static int getN() {
return n;
}

107
Les délégués
 Exemple (3/3) :

public static void Main(string[] args) {


//créer des instances de délégué
operation op1 = new operation(sum);
operation op2 = new operation(sub);

//appèle la méthode sum en utilisant l'objet délégué


op1(10);
Console.WriteLine("La valeur de N est : {0}", getN());

//appèle la méthode sub en utilisant l'objet délégué


op2(2);
Console.WriteLine("La valeur de N est : {0}", getN());
}
}
}
108
Les délégués

 Résultat:

La valeur de N est : 14
La valeur de N est : 12

109
Les événements

 L’une des utilisations les plus importantes des délégués est la


programmation d’événements, notamment dans l’environnement
Windows.

 Les événements permettent à une classe ou à un objet de notifier


d’autres classes ou objets quand quelque chose de significatif se
produit. La classe qui envoie (ou déclenche) l’événement est
appelée publieur et les classes qui reçoivent (ou gèrent) l’événement sont
appelées abonnés.

110
Les événements

 Les événements ont les propriétés suivantes :

• Le publieur détermine quand un événement est déclenché ; les


abonnés déterminent l’action entreprise en réponse à l’événement.

• Un événement peut avoir plusieurs abonnés. Un abonné peut gérer


plusieurs événements provenant de plusieurs publieurs.

• Les événements sont généralement utilisés pour signaler des actions


de l’utilisateur, comme les clics de bouton ou les sélections de menu
dans les interfaces utilisateur graphiques.

• Quand un événement a plusieurs abonnés, les gestionnaires


d’événements sont appelées de façon synchrone quand un événement
est déclenché, c.-à-d. que chaque événement attend la fin du
précédent pour s’exécuter.

• Dans la bibliothèque de classes .NET, les événements sont basés sur


le EventHandler délégué et la EventArgs classe de base.
111
Les événements

 Le mot-clé event protège l’accès au délégué de la manière suivante :

• Il n’est plus possible d’utiliser l’affectation seule (opérateur =), Il


faut donc utiliser += ou -=

• Il n’est pas possible d’appeler le delegate en dehors de la classe où


l’event est déclaré.

112
Utilisation des événements

 On commence par déclarer un délégué à utiliser comme gestionnaire (ou


récepteur) :
delegate void RightButtonDown( object sender, EventArgs e);

 On utilise ensuite le nom du délégué (RightButtonDown) comme type de


l’événement déclaré avec le mot-clé event.

 Par exemple, pour appeler l’événement PressDown, on le définit comme


suit :
event RightButtonDown PressDown;

113
Utilisation des événements
 Exemple 1 (1/2):

using System;

namespace SampleApp {

// Declarer un délégué dans l’espace de nom


public delegate string MyDel(string str);

class EventProgram {
// Declarer un événement en utilisant le délégué
public event MyDel MyEvent;

// Constructeur
public EventProgram() {
this.MyEvent += new MyDel(this.WelcomeUser);
}
// Méthode à exécuter
public string WelcomeUser(string username) {
return "Welcome " + username;
114
}
Utilisation des événements
 Exemple 1 (2/2):

public static void Main(string[] args) {


EventProgram obj1 = new EventProgram();

// L'appel d'un événement ne peut être effectué qu'à partir de la classe


qui a déclaré cet événement.
string result = obj1.MyEvent("Ensa");
Console.WriteLine(result);
}
}
}

 Results :
Welcome Ensa

115
Utilisation des événements
 Exemple 2 (1/3):

116
Utilisation des événements
 Exemple 2 (2/3):

117
Utilisation des événements
 Exemple 2 (3/3):

118
Création initialisation et affectation des objets

Création
 C# fournit un constructeur par défaut
 Ce constructeur permet la création de nouveaux objets
 On pourra définir ses propres constructeurs.

Initialisation
 l ’initialisation doit être prévue par le constructeur de la classe.

Affectation
 Par défaut, l ’affectation de 2 objets de même type correspond à une simple
recopie des valeurs des données membres à membres
Constructeur d’une classe

 Un constructeur est une méthode spéciale qui sert à initialiser un objet


lors de sa création.
 Il porte toujours le nom de la classe pour laquelle il est définie.
 Il est public et n’as pas de type de retour
 Une classe peut avoir un ou plusieurs constructeurs.

120
Auto-référence : le pointeur this
 Le mot réservé this désigne un pointeur, implicitement déclaré, sur l ’objet lui-
même (auto-référence)
 Il peut être utilise dans n ’importe quelle fonction membre et constitue un alias
de l ’objet
Exemple :
class point {
int x,y
public void initialise(int x , int y)
{
this.x=x;
this.y=y;
}
};
Notion de constructeur
 Un constructeur est une fonction membre qui permet de dégager l’utilisateur des
tâches d ’allocation/initialisation.
 Propriétés d ’un constructeur :
 porte toujours le même nom que la classe
 ne renvoie pas de valeur de retour (même pas un void)
 garantit que l ’objet sera toujours initialisé.
class Point
{ int x,y
public point() {x = 20; y = 10;}
void deplace(int dx , int dy) {x = x+dx; y = y+dy;}
void affiche() {Console.WriteLine("x={0}, y={1}", x, y);}
};
class Program
{ static void Main(string[] args)
{
Point a=new Point();
Point b=new Point(); // les deux points sont initialisés en 20,10
a.affiche(); a.deplace(17,10); a.affiche();
Console.ReadKey(); }}
Constructeur d’une classe
Exemple 2
public class personne {
// attributs
private string prenom;
private string nom;
private int age;
// méthode d’initialisation : constructeur
public personne(string P, string N, int age){
prenom=P;
nom=N;
this.age=age;
}/
/ méthode
public void identifie(){
Console.Out.WriteLine(prenom+","+nom+","+age);
}
}

123
Constructeur d’une classe

Il existe trois types de constructeurs :


 Par défaut : pour la création puis l’initialisation d’un objet dans le cas ou
le programmeur omet de donner des valeurs.
 Paramétré: pour la création puis l’initialisation d’un objet avec des
valeurs données par le programmeur .
 Par recopie: pour la création puis l’initialisation d’un objet en copiant les
valeurs d’un autre objet.

124
Constructeur d’une classe

Exemple 3

using System;
public class Personne{
// attributs
private string prenom;
private string nom;
private int age;
// constructeur par défaut
public Personne()
{
this.prenom= "";
this.nom="";
this.age=0;
}

125
Constructeur d’une classe

Exemple 3
// constructeur paramétré
public Personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
} // constructeur par recopie
public Personne(personne P){
prenom=P.prenom;
nom=P.nom;
this.age=P.age
} // méthode
public void identifie(){
Console.Out.WriteLine(prenom+","+nom+","+age);
}
}
126
Constructeur d’une classe

 Voici un court programme de test :


using System;
public class test1{
public static void Main(){
Personne p1=new Personne("Ali","Taha",30);
Console.Out.Write("p1=");
p1.identifie();
Personne p2=new Personne(p1);
Console.Out.Write("p2=");
p2.identifie();
}}
Et les résultats obtenus :
p1=Ali,Taha,30
p2=Ali,Taha,30

127
Passage de paramètres de type référence d'objet par
valeur et par référence
class P12 {
public static void Main() {

StringBuilder sb0 = new StringBuilder("essai0"), sb1 = new StringBuilder("essai1"),


sb2 =new StringBuilder("essai2"), sb3;

Console.WriteLine("Dans fonction appelante avant appel : sb0={0}, sb1={1}, sb2={2}", sb0,sb1, sb2);

ChangeStringBuilder(sb0, sb1, ref sb2, out sb3);

Console.WriteLine("Dans fonction appelante après appel : sb0={0}, sb1={1}, sb2={2}, sb3={3}", sb0,
sb1, sb2, sb3);
}

private static void ChangeStringBuilder(StringBuilder sbf0, StringBuilder sbf1, ref StringBuilder sbf2,
out StringBuilder sbf3) {

Console.WriteLine("Début fonction appelée : sbf0={0}, sbf1={1}, sbf2={2}", sbf0,sbf1, sbf2);

sbf0.Append("*****");
sbf1 = new StringBuilder("essai1*****");
sbf2 = new StringBuilder("essai2*****");
sbf3 = new StringBuilder("essai3*****");

Console.WriteLine("Fin fonction appelée : sbf0={0}, sbf1={1}, sbf2={2}, sbf3={3}", sbf0,


sbf1, sbf2, sbf3);
}
}
128
Passage de paramètres de type référence d'objet
par valeur et par référence

 Résultat d’exécution:

129
Surcharge des opérateurs

 En C# la surcharge des opérateurs arithmétiques présente beaucoup de


différences avec le C++.
 la surcharge d’opérateurs est plus simple, moins permissive mais
moins puissante en C# qu’en C++.
 la quarantaine des opérateurs surchargeables en C++ et en C# il y a
qu’une vingtaine
 Ceux qui n’existent pas en langage C sont :
 les opérateurs «+=» «%=» etc;
 les opérateurs «&&» «|| » ;
 l’opérateur d’affectation « = » ;
 les opérateurs d’allocation/désallocation « new» «delete[]» etc;

130
Surcharge des opérateurs

 Les opérateurs de comparaison doivent être surchargés par paires.


Autrement dit, si l’un des opérateurs d’une paire est surchargé, l’autre doit
également l’être. Il s’agit de paires telles que les suivantes :
-Opérateurs == et !=
-Opérateurs < et >
-Opérateurs <= et >=

 Exemple :
using System;
class Personne
{
…..public static bool operator == (Personnep1, Personnep2)
{ if ((p1.nom == p2.nom) && (p1.age == p2.age))
{return true;}
else{return false;
}
}
131
Surcharge des opérateurs

public static bool operator != (Personnep1, Personnep2)


{ if ((p1.nom != p2.nom) || (p1.age != p2.age))
{ return true;}
else{return false;}
}

public static Personne operator + (Personnep1, Personnep2)


{
return new Personne(p1.nom, p1.age + p2.age);
}

132
Surcharge des opérateurs

public static void Main()


{ Personne p1 = new Personne("Pierre", 40);
Personne p2 = new Personne("Pierre", 40);
Console.WriteLine(p1 == p2);
Personne p3 = p1 + p2;
Console.WriteLine(p3.Age);
Console.WriteLine(p2.Nom);
}

133
L’héritage

 La syntaxe pour l’héritage d’implémentation est la même en C# et C++.


 Conceptuellement il existe une grosse différence entre C++ et C#. C# ne
supporte pas l’héritage multiple.
 Une classe C# ne peut dériver que d’une seule classe de base.
 Une classe C# peut implémenter plusieurs interfaces.
 Exemple :
La syntaxe pour exprimer que la classe Enseignant hérite des propriétés
de la classe Personne est la suivante :

// La classe Enseignant hérite de la classe Personne.


class Enseignant : Personne{
...
}
134
L’héritage

Le niveau de visibilité « protected » :


 C# permet de protéger des membres d’une classe de base. La notion de
protection d’un membre est identique entre C++ et C# .
 Le mot-clé est aussi le mot « protected », et la seule différence est qu’en
C# il faut écrire ce mot-clé pour chaque membre protégé.

135
L’héritage
Appels aux constructeurs de la classe de base :
 Un constructeur de la classe dérivé peut utiliser le mot clé « base » pour
appeler le constructeur d’une classe de base.
 le constructeur de la classe de base est appelé avant que le bloc du
constructeur de la classe dérivé ne soit exécuté.
 Exemple :

public class Enseignant : Personne


{
public Enseignant(string Prenom, string Nom, int age)
: base(Prenom, Nom, age)
{
//Add further instructions here.
}
}

136
L’héritage

 Le mot clé « base » peut être utilisé avec ou sans paramètres.


 Dans une classe dérivée, si un constructeur de classe de base n’est pas
appelé explicitement à l’aide du mot clé base, le constructeur sans
paramètre, s’il existe, est appelé implicitement.
 Cela signifie que les déclarations de constructeur suivantes sont en fait les
mêmes :
public Enseignant(string Prenom, string Nom, int age)
{
//Add further instructions here.
}

public Enseignant(string Prenom, string Nom, int age)


: base()
{
//Add further instructions here.
}
 Si une classe de base n’offre pas de constructeur sans paramètre, la classe
dérivée doit faire un appel explicite à un constructeur de base à l’aide de
« base ». Sinon une erreur de compilation sera générée.
137
L’héritage

using System;
public class etudiant: personne {
// attributs
private CNE;
// constructeur
public etudiant(string P, string N, int age,int CNE) : base(P,N,age) {
this.CNE=CNE;
// suivi
Console.Out.WriteLine("Construction etudiant(string,string,int,int)");
}//constructeur
// propriété CNE
public CNE{
get { return CNE; }
set { CNE=value; }
}// CNE
}//classe

138
Redéfinition de méthodes et de propriétés

 La redéfinition de méthodes est spécifique aux langages orientés objet. Elle


est mise en œuvre lors de l'héritage d'une classe mère vers une classe fille
dans le cas d'une méthode ayant la même signature dans les deux classes.
Dans ce cas les actions dûes à l'appel de la méthode, dépendent du code
inhérent à chaque version de la méthode (celle de la classe mère, ou bien celle
de la classe fille).

 La redéfinition de propriétés est similaire à la redéfinition de méthodes.


Tout ce qui sera dit sur la redéfinition de méthodes est aussi applicable sur la
redéfinition de propriétés.

139
Redéfinition de méthodes

Dans l’exemple ci-dessous, nous supposons que dans la classe PortesEtFenetres


la méthode ouvrir(fenetre) explique le mode opératoire général d'ouverture d'une
fenêtre, il est clair que dans les deux classes descendantes l'on doit "redéfinir" le
mode opératoire selon que l'on est en présence d'une fenêtre à la française, ou une
fenêtre à l'anglaise :

140
Redéfinition de méthodes

 La redéfinition de méthode peut être selon les langages :


- Précoce (liaison statique)

et/ou

- Tardive (liaison dynamique)

141
Redéfinition de méthodes

 Dans la liaison statique ou précoce le compilateur du langage met


en place la liaison du code de la méthode immédiatement lors de la
compilation.

Dans la liaison dynamique ou tardive la liaison du code de la


méthode est faite lors de l’exécution.

142
Redéfinition de méthodes

 Le langage C# supporte les deux modes de liaison du code, la liaison


statique étant le mode par défaut.

 Le développeur Java sera plus décontenancé sur ce sujet, car la liaison


statique en Java n'existe que pour les méthodes de classe static, de plus la
liaison du code par défaut est dynamique en Java.

 Donc en C#, des mot clés comme virtual et override sont nécessaires pour
la redéfinition des méthodes.

143
Liaison statique et masquage

 Toute méthode C# qui n’est précédée d’aucun des deux qualificateurs


virtual ou override est à liaison statique.

 Le compilateur détermine l'adresse exacte de la méthode et lie la méthode


au moment de la compilation.

 Exemple : Dans l'exemple ci-dessous, les trois méthodes P,Q et R sont à


liaison statique dans leur déclaration par défaut sans utiliser de qualificateur
spécial.

class A {
public void P( int x, int y ){ }
private void Q( string a, string b, string c ){ }
protected void R( ){ }
}

144
Liaison statique et masquage

Si vous déclarez dans une classe dérivée de la classe de base A, une méthode
ayant le même nom qu'une méthode à liaison statique de la classe de base, la
nouvelle méthode remplace simplement la méthode héritée dans la classe
dérivée.

Dans ce cas nous emploierons aussi le mot de masquage qui semble être
utilisé pour dénommer ce remplacement, car il correspond bien à l'idée d'un
masquage "local" dans la classe fille du code de la méthode de la classe
parent par le code de la méthode fille.

145
Liaison statique et masquage

Exemple :
// Classe Fille
// Classe Mère public class Automobile : Vehicule
public class Vehicule {
{ private string couleur;
private int poids;
// Constructeur
// Constructeur public Automobile(int poids,string
public Vehicule(int poids) couleur) : base(poids)
{ this.poids = poids; } { this.couleur = couleur; }

// Méthode à liaison statique // méthode à liaison statique redéfinie


public string Description() public string Description()
{ {
return "Véhicule de "+poids+" tonnes"; return base.Description()+" de
} couleur "+couleur;
}
} // Fin classe mère
} // Fin classe fille
146
Liaison statique et masquage

Exemple :
// Classe Fille
// Classe Mère public class Automobile : Vehicule
public class Vehicule {
{ private string couleur;
Le compilateur génère un avertissement
private int poids;
(warning CS0108) dans la classe dérivée.
// Constructeur
public Automobile(int poids,string
// Constructeur  Il faut spécifier que l'on redéfinit une
public Vehicule(int poids) couleur) : base(poids)
méthode, en utilisant le mot clé new
{ this.poids = poids; } { this.couleur = couleur; }

// Méthode à liaison statique // méthode à liaison statique redéfinie


public string Description() public string Description()
{ {
return "Véhicule de "+poids+" tonnes"; return base.Description()+" de
} couleur "+couleur;
}
} // Fin classe mère
} // Fin classe fille
147
Liaison statique et masquage

Exemple: Ajout du mot clé « new »

// Classe Fille
public class Automobile : Vehicule
{
private string couleur;

// Constructeur
public Automobile(int poids,string couleur) : base(poids)
{ this.couleur = couleur; }

// méthode à liaison statique redéfinie


public new string Description()
{
return base.Description()+" de couleur "+couleur;
}

} // Fin classe fille

148
Liaison statique et masquage

 Usage de la méthode « Description»


Automobile voiture = new Automobile(3, "rouge");
Console.WriteLine(voiture.Description());

Vehicule vehicule = new Automobile(3, "rouge");


Console.WriteLine( vehicule.Description() );

 Résultat :
Véhicule de 3 tonnes de couleur rouge Le masquage
Véhicule de 3 tonnes La méthode appelée est celle de la classe mère.
Que fait alors le compilateur C# dans ce cas ?  il
réalise une liaison statique.

149
Liaison statique et masquage

Lors de la compilation de l'instruction voiture.Description(), c'est le


code de la méthode Description ( ) de la classe fille Automobile qui est lié.

 Lors de la compilation de l'instruction vehicule.Description(), c'est le


code de la méthode Description ( ) de la classe mère Vehicule qui est lié,
car la référence vehicule a été déclarée de type Vehicule et peu importe
dans quelle classe elle a été instanciée.

150
Liaison statique et masquage

Le compilateur se base sur le type de la référence plutôt que sur le type
réel de l'objet référencé.

Une conversion de la référence vers la classe réelle de l'objet permet


d'appeler la méthode redéfinie :

Console.WriteLine( ((Automobile)vehicule).Description());

// Résultat : Véhicule de 3 tonnes de couleur rouge

 Si on ne veut pas passer par la conversion de la référence pour faire


appel aux méthodes de la classe réelle de l’objet, il faut faire appel à la
liaison dynamique.

151
Liaison dynamique

 Un type dérivé peut redéfinir une méthode à liaison dynamique héritée.


On appelle aussi virtuelle une telle méthode à liaison dynamique, nous
utiliserons donc souvent ce raccourci de notation pour désigner une
méthode redéfinie dynamiquement.

 L'action de redéfinition fournit une nouvelle définition de la


méthode qui sera appelée en fonction du type de l'objet au moment de
l'exécution et non du type de la variable de référence connue au moment
de la compilation.

152
Liaison dynamique

- Pour faire appel à la liaison dynamique:

La méthode à redéfinir doit être déclarée avec le mot-clé virtual, dans la
première classe de base qui l’implémente, et;

 Dans chaque classe dérivée où la méthode virtuelle est redéfinie, il faut


faire précéder la méthode du mot-clé override.

153
Liaison dynamique

Exemple :
// Classe Fille
// Classe Mère public class Automobile : Vehicule
public class Vehicule {
{ private string couleur;
private int poids;
// Constructeur
// Constructeur public Automobile(int poids,string
public Vehicule(int poids) couleur) : base(poids)
{ this.poids = poids; } { this.couleur = couleur; }

// Méthode à liaison dynamique // méthode à liaison dynamique redéfinie


public virtual string Description() public override string Description()
{ {
return "Véhicule de "+poids+" tonnes"; return base.Description()+" de
} couleur "+couleur;
}
} // Fin classe mère
} // Fin classe fille
154
Liaison dynamique

 Usage de la méthode « Description»


Vehicule vehicule = new Automobile(3, "rouge");
Console.WriteLine( vehicule.Description() );

 Résultat :
Véhicule de 3 tonnes de couleur rouge La liaison dynamique.

155
Liaison dynamique

 Exemple :
Une classe de base Employe et deux classes dérivées Technicien et Secretaire.

156
Liaison dynamique

public class Employe


{
protected string m_Nom;
public Employe(string nom) { m_Nom = nom; }
public virtual void DisplayDescription()
{
System.Console.Write("Nom : {0}", m_Nom);
}
}

157
Liaison dynamique

class Secretaire : Employe


{ // Secretaire herite de Employe.
public Secretaire(string nom) : base(nom) { }
public override void DisplayDescription()
{
// Appel de la methode DisplayDescription() de Employe.
base.DisplayDescription();
System.Console.Write(" Fonction : Secretaire\n");
}
}

158
Liaison dynamique

class Technicien : Employe


{ // Technicien herite de Employe.
public Technicien(string nom) : base(nom) { }
public override void DisplayDescription()
{
// Appel de la methode DisplayDescription() de Employe.
base.DisplayDescription();
System.Console.Write(" Fonction : Technicien\n");
}
}

159
Liaison dynamique

class Program{
static void Main()
{
Employe[] tableau = new Employe[3];
tableau[0] = new Technicien("Line");
tableau[1] = new Secretaire("Lisanette");
tableau[2] = new Secretaire("Anne-Mette");
foreach (Employe employe in tableau)
employe.DisplayDescription();
}
}

Voici ce qu’affiche ce programme :


Nom : Line Fonction : Technicien
Nom : Lisanette Fonction : Secretaire
Nom : Anne-Mette Fonction : Secretaire
160
Classes et méthodes « sealed »

 Lorsqu’on précède une classe par le modificateur « sealed », ceci empêche


les autres classes d’hériter de cette classe.

Exemple : La classe B hérite de la classe A, mais aucune classe ne peut


hériter de la classe B car B est déclarée « sealed »

class A { }
sealed class B : A { }
class C : B { } // Error : ‘C': cannot derive from sealed type ‘B'

161
Classes et méthodes « sealed »

 Vous pouvez également utiliser le modificateur « sealed » sur une méthode


ou une propriété qui redéfinie une méthode virtuelle ou une propriété dans
une classe de base. Cela vous permet d'autoriser les classes à dériver de votre
classe et de les empêcher de redéfinir des méthodes ou des propriétés
virtuelles spécifiques.

 Lorsqu’il est utilisé avec une méthode ou une propriété, le mot clé
« sealed » doit être toujours combiné avec le mot clé « override ».

162
Classes et méthodes « sealed »

 Exemple:
class X
{
protected virtual void F() { Console.WriteLine("X.F"); }
protected virtual void F2() { Console.WriteLine("X.F2"); }
}
class Y : X
{
sealed protected override void F() { Console.WriteLine("Y.F");}
protected override void F2() { Console.WriteLine("Y.F2"); }
}

class Z : Y
{
// Error CS0239 :’Z.F()’ Impossible de substituer le membre
hérité ‘Y.F()’ car il est sealed .
protected override void F() { Console.WriteLine("Z.F"); }
// Overriding F2 is allowed.
protected override void F2() { Console.WriteLine("Z.F2"); }
}
163
Abstraction

 Le concept d’abstraction est complètement similaire entre les langages


C# et C++. Cependant des différences de syntaxe apparaissent, et même
de vocabulaire.

 Une classe abstraite a besoin au moins d’une méthode abstraite pour


être abstraite.

 Une classe abstraite est une classe qui doit déléguer complètement
l’implémentation de certaines de ces méthodes à ses classes dérivées.

 Les méthodes abstraites seront déclarées avec le mot-clé abstract en


préfixe et doivent être contenues dans des classes abstraites, déclarées
aussi avec le mot-clé abstract en préfixe

164
Abstraction

 Une méthode abstraite n’est qu’une méthode virtuelle particulière, et


doit être implémentée dans les classes dérivées avec le mot-clé override
en préfixe (ou override sealed).

 Si une classe dérivée d’une classe abstraite n’implémente pas toutes les
méthodes abstraites, elle est elle-même abstraite.

 Une classe abstraite n’est pas instanciable.

 Il ne peut y avoir d’objets instances d’une classe abstraite, mais une


référence peut avoir pour type une classe abstraite.

 Le polymorphisme est plus évident lorsqu’il est utilisé sur des méthodes
abstraites.

 Une méthode abstraite ne doit pas avoir une visibilité privée.


165
Abstraction

 Exemple :
- Une classe de base abstraite Figure Geometrique,
- Deux classes dérivée Cercle et Triangle,
- Un traitement de base qui est de dessiner la figure.

class Point
{
public Point (int x,int y){
this.x = x;this.y = y;
}
int x ; int y ;
}

abstract class FigureGeometrique


{
// On verifie qu’une m´ethode abstraite n’a pas de corps.
public abstract void Dessine();
}

166
Abstraction

class Cercle : FigureGeometrique


{
private Point m_Centre ;
private double m_Rayon ;
public Cercle(Point centre, double rayon)
{
m_Centre = centre ;
m_Rayon = rayon ;
}
public override void Dessine ()
{ // Dessine un Cercle `a partir de son centre
et de son rayon.
}
}

167
Abstraction

class Triangle : FigureGeometrique {


private Point m_Sommet1 ;
private Point m_Sommet2 ;
private Point m_Sommet3 ;

public Triangle(Point s1, Point s2, Point s3)


{
m_Sommet1 = s1;
m_Sommet2 = s2;
m_Sommet3 = s3;
}
public override void Dessine()
{
// Dessine un Triangle `a partir de trois de ses
sommets.
}
}

168
Abstraction

class Program{
static void Main(){
FigureGeometrique[] tableau = new FigureGeometrique[3];
tableau[0] = new Cercle(new Point(0, 0), 3.2);
tableau[1] = new triangle(
new Point(0, 0), new Point(0, 2), new Point(1, 2));
tableau[2] = new Cercle(new Point(1, 1), 4.1);
// Le polymorphisme s’applique `a l’appel
// de la methode abstraite Dessine().
foreach (FigureGeometrique f in tableau)
f.Dessine();
}
} Remarque : on ne peut pas écrire cette instruction
FigureGeometrique fig = new FigureGeometrique();
Une classe abstraite n’est pas instanciable

169
Interfaces

 Une interface définie un contrat


 Elle contient des méthodes, propriétés, indexeurs, évènements.
 Chaque classe implémentant une interface doit supporter toute les
parties du contrat.

 Une interface ne contient pas d’implémentation


 Elle doit être implémentée par une classe ou une structure.

 Les interfaces permettent le polymorphisme


 Plusieurs classes et structures peuvent implémenter la même
interface.

 Les membres de l’interface sont publics par défaut.

170
Interfaces

 Une interface peut déclarer des méthodes, des


propriétés, des indexeurs et des events.

Public Interface IExemple


{
// Méthode à implémenter :
void UneMethodeAImplementer ();

// Propriétés à implémenter :
string UneProprieteAImplementer {get; set;}
string UneProprieteLectureSeuleAImplementer {get;}

// Tableau de string à implémenter (indexeur) :


string this [int index] {get; set;}

// Evénements à implémenter
event PageRecueDelagate PageRecue {add; remove;}
}

171
Implémentation de l’interface

 Une interface peut être implémentée par une classe ou


une structure comme le montre cet exemple :

class MaClasse:IMonInterface
{
// implémentation de la classe
}

 Par cette déclaration, la classe MaClasse est tenue de


mettre en oeuvre tous les membres de l’interface
IMonInterface.

172
Implémentation de l’interface

 Une classe peut implémenter plus d'une interface:


 Une classe peut également implémenter une autre classe
en plus des interfaces:

class MaClasse: MaBaseClasse, IMonInterface1,


IMonInterface2
{
// implémentation de la classe
}

173
Implémentation de l’interface

 Exemple (1/4) :
interface IPoint
{
// Propriétés :
int MonX
{
get; set;
}
int MonY
{
get; set;
}
}

174
Implémentation de l’interface

 Exemple (2/4) :
class Point : IPoint
{
// Champs:
private int x;
private int y;
// Constructeur:
public Point(int x, int y)
{
this.x = x;
this.y = y;
}

175
Implémentation de l’interface
 Exemple (3/4) :
// implementation des propriétés :
public int MonX
{
get { return x; }
set { x = value; }
}
public int MonY
{
get { return y; }
set { y = value; }
}
public static void AfficherMonPoint(IPoint monPoint)
{
Console.WriteLine("({0},{1})", monPoint.MonX,
monPoint.MonY);
}
} 176
Implémentation de l’interface

 Exemple (4/4) :
class MaClasse
{
static void Main()
{
Point monPoint = new Point(12, 300);
Console.Write("Mon point est créé avec les
coordonnées: ");
Point.AfficherMonPoint(monPoint);
}
}

177
Implémentation d’interface explicite

 Si une classe implémente deux interfaces qui contiennent un membre avec la


même signature, l'implémentation de ce membre sur la classe fera en sorte
que les deux interfaces utilisent ce membre comme leur implémentation.

 Par exemple :

interface IControl
{
void Paint();
}
interface ISurface
{
void Paint();
}
class SampleClass : IControl, ISurface
{
// ISurface et IControl contiennent la même méthode
Paint
Public void Paint()
{
}
}

178
Implémentation d’interface explicite

 Il est possible d'implémenter un membre d'interface explicitement:


 Créer un membre de classe qui n'est appelé qu'à travers l'interface en
le nommant avec le nom de l'interface et un point.

public class SampleClass : IControl, ISurface


{
void Icontrol.Paint()
{
System.Console.WriteLine(" IControl.Paint ");
}
void ISurface.Paint()
{
System.Console.WriteLine(" Isurface.Paint ");
}

179
Implémentation d’interface explicite

 Le membre de classe IControl.Paint est uniquement disponible à travers


l'interface IControl, et ISurface.Paint est uniquement disponible à travers
ISurface.

 Les deux implémentations de méthode sont distinctes, et aucune n'est


directement disponible sur la classe.

SampleClass obj = new SampleClass();


//obj.Paint() : erreur de compilation
IControl c = (Icontrol)obj;
c.Paint(); //appelle IControl.Paint()
ISurface s = (Isurface)obj;
s.Paint(); //appelle ISurface.Paint()

180
Implémentation d’interface explicite

 L'implémentation explicite est également utilisée pour résoudre les cas où


deux interfaces déclarent chacune des membres différents du même nom,
comme une propriété et une méthode :

interface ILeft
{
int P ( get;)
}
interface IRight
{
int P ();
}
class Middle : ILeft, IRight
{
int P() { return 0;}
int Ileft.P { get { return 0;}}
}

 Pour implémenter les deux interfaces, la classe Middle doit utiliser


l'implémentation explicite pour la propriété P, la méthode P, ou les deux, pour
éviter une erreur du compilateur.
181
Héritage entre interfaces
 Une interface peut hériter d'une autre interface. Elle possède donc les mêmes
déclarations que l'interface de base en plus de ces propres déclarations.

182
Utiliser « is » pour tester les types

 Usage :

expression is type
où:
type est une référence à un type
Expression est l’objet à tester

 Le résultat est true ou false

183
Utiliser « is » pour tester les types

 Exemple (1/2):

interface I1{
}
interface I2{
}
class Class1 : I1, I2{
}
class MaClasse
{
static bool TesterType(object obj)
{
if (obj is I1 & obj is I2 & obj is Class1)
return true;
else
return false;
}
184
Utiliser « is » pour tester les types

 Exemple (2/2):

public static void Main()


{
Class1 c = new Class1();
Console.WriteLine("Le résultat du test est: {0}",
TesterType(c));
}
}

185
La gestion des exceptions

 De nombreuses fonctions C# sont susceptibles de générer des exceptions,


c'est à dire des erreurs.

 Lorsqu'une fonction est susceptible de générer une exception, le


programmeur devrait la gérer dans le but d'obtenir des programmes plus
résistants aux erreurs.

 Il faut toujours éviter le "plantage" sauvage d'une application.

186
La gestion des exceptions

 La gestion d'une exception se fait selon le schéma suivant :


Try
{
appel de la fonction susceptible de générer l'exception
}
catch (Exception e)
{
traiter l'exception e
}
instruction suivante

187
La gestion des exceptions

 Si la fonction ne génère pas d'exception, on passe alors à l’instruction


suivante, sinon on passe dans le corps de la clause catch puis à
l’instruction suivante.

 Notons les points suivants :


e est un objet dérivé du type Exception.
On peut être plus précis en utilisant des types tels que IOException,
SystemException, etc… : il existe plusieurs types d'exceptions.
En écrivant catch (Exception e), on indique qu'on veut gérer toutes
les types d'exceptions.

188
La gestion des exceptions
 Si le code de la clause try est susceptible de générer plusieurs types
d'exceptions, on peut vouloir être plus précis en gérant l'exception avec
plusieurs clauses catch :
try {
appel de la fonction susceptible de générer
l'exception
} catch (IOException e){
traiter l'exception e
}
} catch (SystemException e){
traiter l'exception e
}
instruction suivante

189
La gestion des exceptions

 Dans la clause catch, on peut ne pas vouloir utiliser l'objet Exception


disponible. Au lieu d'écrire catch (Exception e){..}, on écrit alors
catch (Exception){...} ou catch {...}.
 On peut ajouter aux clauses try/catch, une clause finally :
try{
appel de la fonction susceptible de générer l'exception
} catch (Exception e){
traiter l'exception e
}
finally{
code exécuté après try ou catch
}
instruction suivante
 Qu'il y ait exception ou pas, le code de la clause finally sera toujours
exécuté.

190
La gestion des exceptions

 La classe Exception a une propriété Message qui est un message détaillant


l'erreur qui s'est produite. Ainsi si on veut afficher celui-ci, on écrira :
catch (Exception ex){
Console.Error.WriteLine("L'erreur suivante s'est produite :
"+ex.Message);
...
}//catch
 La classe Exception a une méthode ToString qui rend une chaîne de
caractères indiquant le type de l'exception ainsi que la valeur de la
propriété Message. On pourra ainsi écrire :
catch (Exception ex){
Console.Error.WriteLine("L'erreur suivante s'est produite :
"+ex.ToString());
...
}//catch

191
Exemple 1

using System;
public class Prog
{
public static void Main()
{
try
{
int i = 1;
int j = 0;
int k = i/j;
}
catch(System.DivideByZeroException)
{
Console.WriteLine("Une division entière par zéro a eu lieu!");
}
}
}

192
Exemple 2

 L'exemple suivant montre une exception générée par l'utilisation d'un


élément de tableau inexistant :
// tableaux
// imports
using System;
public class tab1 {
public static void Main(String[] args){
// déclaration & initialisation d'un tableau
int[] tab=new int[] {0,1,2,3};
int i;
// affichage tableau avec un for
for (i=0; i<tab.Length; i++)
Console.Out.WriteLine("tab[" + i + "]=" + tab[i]);

193
Exemple 2

// affichage tableau avec un foreach


foreach (int élmt in tab)
Console.Out.WriteLine(élmt);
// génération d'une exception
try{
tab[100]=6;
}
catch (Exception e){
Console.Error.WriteLine("L'erreur suivante s'est produite : " + e.Message);
}//try-catch
finally{
String attente=Console.ReadLine();
}
}//Main
}//classe

194
Résultat de l’exemple

tab[0]=0
tab[1]=1
tab[2]=2
tab[3]=3
0
1
2
3
L'erreur suivante s'est produite : Index was outside the bounds of the array.

195
Exemple 3
class Program
{
static void Main(string[] args){
// On demande le nom
Console.Write("Nom : ");
// lecture réponse
string nom = Console.ReadLine();
// on demande l'âge
int age = 0;
bool ageOK = false;
while (!ageOK) {
// question
Console.Write("âge : ");
// lecture-vérification réponse
try {
age = int.Parse(Console.ReadLine());
ageOK = age>=1;
} catch {
}//try-catch
if (!ageOK) {
Console.WriteLine("Age incorrect, recommencez...");
}
}//while
// affichage final
Console.WriteLine("Vous vous appelez {0} et vous avez {1} an(s)",nom,age);
}} 196
Exemple 3
class Program
{ Résultat de l’exemple
static void Main(string[] args){
// On demande le nom Nom : Sara
Console.Write("Nom : ");
âge : 23
// lecture réponse
string nom = Console.ReadLine(); Vous vous appelez Sara et
// on demande l'âge vous avez 23 an(s)
int age = 0;
bool ageOK = false;
while (!ageOK) {
Nom : Ahmed
// question âge : x
Console.Write("âge : "); Age incorrect, recommencez...
// lecture-vérification réponse
âge : -4
try {
age = int.Parse(Console.ReadLine()); Age incorrect, recommencez...
ageOK = age>=1; âge : 12
} catch { Vous vous appelez Ahmed et
}//try-catch
if (!ageOK) {
vous avez 12 an(s)
Console.WriteLine("Age incorrect, recommencez...");
}
}//while
// affichage final
Console.WriteLine("Vous vous appelez {0} et vous avez {1} an(s)",nom,age);
}} 197
Exemple 4
//espace de noms importés
Using System;
//La classe de test
namespace Test1
{
class Program
{
static void Main(string[] args)
{ string s;
const int i = 10;
const long l = 10000;
const float f = 45.78F;
double d = -14.98;
//Nombrechaine
s = "" + i;
Console.WriteLine(s);
s = "" + l;
Console.WriteLine(s);
s = "" + f;
Console.WriteLine(s);
s = "" + d;
Console.WriteLine(s);

198
Exemple 4
//Boolean-->chaine
const bool b = false;
s = "" + b;
Console.WriteLine(s);
//chaine-->int
int i1;
i1 = int.Parse("10");
Console.WriteLine("" + i1);
try
{ i1 = int.Parse("10.67");
Console.WriteLine("" + i1); }
catch(Exception e)
{ Console.WriteLine("Erreur"+e.Message); }
//chaine-->long
long l1;
l1=long.Parse("100");
Console.WriteLine(""+l1);
try
{
l1=long.Parse("10.675");
Console.WriteLine(""+l1);
}
catch(Exception e)
{
Console.WriteLine(" Erreur"+e.Message); }
199
Exemple 4
//Chaine-->double
double d1;
d1=double.Parse("100,87");
Console.WriteLine("" + d1);
try
{ d1 = double.Parse("abcd");
Console.WriteLine("" + d1); }
catch (Exception e)
{ Console.WriteLine("Erreur" + e.Message); }
//Chaine --> float
float f1;
f1 = float.Parse("100,87");
Console.WriteLine ("" + f1);
try
{
d1 = float.Parse("abcd");
Console.WriteLine("" + f1);
}
catch (Exception e)
{ Console.WriteLine("Erreur" + e.Message); }
Console.ReadKey();
}
}
}

200
Exécution de l’exemple 4

 Les résultats obtenus sont les suivants :


S=10
S=10000
S=45,78
S=-14,98
S=False
S=10
S=Erreur Input string was not in a correct format.
S=100
S=Erreur Input string was not in a correct format.
S=100,87
S=Erreur Input string was not in a correct format.
S=100,87
S=Erreur Input string was not in a correct format.
 On remarquera que les nombres réels sous forme de chaîne de
caractères doivent utiliser la virgule et non le point décimal. Ainsi on
écrira double d1=10.7; mais double d2=int.Parse("10,7");

201
Troisième partie.

INTERFACES GRAPHIQUES AVEC


C# ET VS.NET
L’espace de noms System.Windows.Forms

L’espace de noms System.Windows.Forms contient de nombreuses


classes utilisées pour créer des applications graphiques Windows. Ces
classes peuvent être réparties en cinq groupes :

Les formulaires : Ce sont les classes qui contiennent les comportements


de base des formulaires. On peut citer la classe
System.Windows.Forms.Form, qui représente la classe de base pour tous
les formulaires.

Les contrôles : Un contrôle est un élément d’un formulaire. Une trentaine


de types de contrôles classiques sont fournis par le framework .NET( le
bouton ou la zone d’édition de texte. Ils ont tous la particularité de dériver
de la classe System.Windows.Forms.Control.

203
L’espace de noms System.Windows.Forms

 Les composants : Dans le domaine des applications graphiques, les


composants permettent de rajouter des fonctionnalités à vos formulaires Par
exemple la classe System.Windows.Forms.ToolTip. La classe de base de
tous les composants est la classe System.ComponentModel.Component.

Les fenêtres de dialogues usuels : De nombreux dialogues usuels sont


directement encapsulés dans des classes de base du framework .NET. On
peut citer le dialogue de choix d’un fichier, le dialogue de choix de fontes, le
dialogue de choix d’une couleur.

Les classes d’aide au développement de formulaires : De nombreux types


sont nécessaires pour développer des formulaires( le style des contrôles ou
des formulaires).

204
Formulaire
using System;
using System.Drawing;
using System.Windows.Forms;
// la classe formulaire
public class Form1 : Form {
// le constructeur
public Form1() {
// titre de la fenêtre
this.Text = "Mon premier formulaire";
// dimensions de la fenêtre
this.Size=new
System.Drawing.Size(300,100);
}//constructeur
// fonction de test
public static void Main(string[] args) {
// on affiche le formulaire
Application.Run(new Form1());
}
}//classe
205
Un formulaire avec bouton

using System;
using System.Drawing;
using System.Windows.Forms;
// la classe formulaire
public class Form1 : Form {
// attributs
Button cmdTest;
// le constructeur
public Form1() {
// le titre
this.Text = "Mon premier formulaire";
// les dimensions
this.Size=new System.Drawing.Size(300,100);

206
Un formulaire avec bouton

// création bouton
this.cmdTest = new Button();
// position bouton
cmdTest.Location = new
System.Drawing.Point(110, 20);
// taille bouton
cmdTest.Size = new System.Drawing.Size(80,30);

207
Un formulaire avec bouton

// libellé
cmdTest.Text = "Test";
// gestionnaire d'évt
cmdTest.Click += new System.EventHandler(cmdTest_Click);
// ajout bouton au formulaire
this.Controls.Add(cmdTest);
}//constructeur
// gestionnaire d'événement
private void cmdTest_Click(object sender, EventArgs evt){
// il y a eu un clic sur le bouton - on le dit

208
Un formulaire avec bouton

MessageBox.Show("Clic sur bouton", "Clic sur bouton",


MessageBoxButtons.OK,MessageBoxIcon.Information);

}//cmdTest_Click
// fonction de test
public static void Main(string[] args) {
// on affiche le formulaire
Application.Run(new Form1());
}
}//classe

209
Un formulaire avec bouton

Nous avons rajouté au formulaire un bouton :


// création
this.cmdTest = new Button();
// position
cmdTest.Location = new System.Drawing.Point(110, 20);
// taille
cmdTest.Size = new System.Drawing.Size(80, 30);
// libellé
cmdTest.Text = "Test";
// gestionnaire d'évt
cmdTest.Click += new System.EventHandler(cmdTest_Click);
// ajout bouton au formulaire
this.Controls.Add(cmdTest);

210
Un formulaire avec bouton

La propriété Location fixe les coordonnées (110,20) du point supérieur


gauche du bouton à l'aide d'une structure Point.
La largeur et l’hauteur du bouton sont fixées à (80,30) à l'aide d'une
structure Size.
La propriété Text du bouton permet de fixer le libellé du bouton.
Ici, lors d'un clic sur le bouton cmdTest, la méthode
cmdTest_Click sera appelée.

private void cmdTest_Click(object sender, EventArgs evt)


{
MessageBox.Show("Clic sur bouton", "Clic sur bouton",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}//cmdTest_Click

211
Un formulaire avec bouton

On se contente d'afficher un message :

212
La classe MessageBox

La classe MessageBox sert à afficher des messages dans une fenêtre.


La signature de la méthode show est comme suit:

public static System.Windows.Forms.DialogResult Show(string text,


string caption, System.Windows.Forms.MessageBoxButtons buttons,
System.Windows.Forms.MessageBoxIcon icon);

avec:
• text le message à afficher
• caption le titre de la fenêtre
• buttons les boutons présents dans la fenêtre
• icon l'icône présente dans la fenêtre

213
Un formulaire avec bouton

Buttons peut prendre une des valeurs suivantes:


MessageBoxButtons.OK
MessageBoxButtons.AbortRetryIgnore
MessageBoxButtons.OKCancel
MessageBoxButtons.RetryCancel
MessageBoxButtons.YesNo
MessageBoxButtons.YesNoCancel
Exemple :

214
Un formulaire avec bouton

Les icones peuvent être:


MessageBoxIcon.Information
MessageBoxIcon.Exclamation
MessageBoxIcon.Error
MessageBoxIcon. Question
MessageBoxIcon.warning
Etc..
Exemple :

215
Applications Windows

Lors de la création d’un projet Windows avec visual studio, ce dernier


fournit une feuille (Form) sur laquelle viendront glisser tous les contrôles
visuels.
En prenant des contrôles dans la barre d'outils Toolbox et en les déposant
sur la surface de la fenêtre Form1,
nous pouvons construire une interface graphique.

216
Applications Windows

Si nos amenons la souris sur la "toolbox" celle-ci s'agrandit et laisse


apparaître un certain nombre de contrôles :

217
Applications Windows

 Une interface graphique dérive de la classe de base


System.Windows.Forms.Form :
 La classe de base Form définit une fenêtre de base avec des boutons
de fermeture, agrandissement/réduction, une taille ajustable, ...et
gère les événements sur ces objets graphiques.
 Le constructeur du formulaire utilise une méthode
InitializeComponent dans laquelle les contrôles du formulaires sont
créés et initialisés.
public Form1()
{
InitializeComponent();
// autres initialisations
}
218
Applications Windows

 Tout autre travail à faire dans le constructeur peut être fait après l'appel
à InitializeComponent. La méthode InitializeComponent
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "Form1";
}
 fixe le titre de la fenêtre "Form1", sa largeur (300) et sa hauteur (300).
 Le titre de la fenêtre est fixée par la propriété Text.
 et les dimensions par la propriété Size. Size est défini dans l'espace de
noms System.Drawing et est une structure.
219
Applications Windows

 La fonction Main lance l'application graphique de la


façon suivante :
 Application.Run(new Form1());
 Un formulaire de type Form1 est créé et affiché, puis
l'application se met à l'écoute des événements qui se
produisent sur le formulaire (clics, déplacements de souris,
etc..) et fait exécuter ceux que le formulaire gère.

220
Le formulaire Form

 Le formulaire Form est le plus important des composants car c’est


sur un formulaire qu’on on dépose des composants.
 Nous nous attardons ici sur quelques événements importants d'un
formulaire.
 Load le formulaire est en cours de chargement
 Closing le formulaire est en cours de fermeture
 Closed le formulaire est fermé
 L'événement Load se produit avant même que le formulaire ne soit
affiché.
 L'événement Closing se produit lorsque le formulaire est en cours de
fermeture.

221
Le formulaire Form
Nous traitons les trois événements précédents :

private void Form1_Load(object sender, System.EventArgs e) {


// chargement initial du formulaire
MessageBox.Show("Evt Load","Load");
}
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e) {
// le formulaire est en train de se fermer
MessageBox.Show("Evt Closing","Closing");
// on demande confirmation
DialogResult réponse=MessageBox.Show("Voulez-vous vraiment quitter
l'application","Closing",MessageBoxButtons.YesNo,MessageBoxIcon.Question
);
if(réponse==DialogResult.No) e.Cancel=true;
}
private void Form1_Closed(object sender, System.EventArgs e) {
// le formulaire est en train de se fermer
MessageBox.Show("Evt Closed","Closed");
} 222
Le formulaire Form

 Nous utilisons la fonction


MessageBox pour être averti des
différents événements.
 L'événement Closing va se
produire lorsque l'utilisateur ferme
la fenêtre.
 Nous lui demandons alors s'il veut
vraiment quitter l'application:
 S'il répond Non, nous fixons la
propriété Cancel de l'événement
CancelEventArgs e que la méthode
a reçu en paramètre. Si nous
mettons cette propriété à False, la
fermeture de la fenêtre est
abandonnée, sinon elle se poursuit
:
223
Étiquettes Label et boîtes de saisie TextBox

 Label est un composant texte et TextBox un composant champ de


saisie.
 Leur propriété principale est Text qui désigne soit le contenu du
champ de saisie ou le texte du libellé. Cette propriété est en
lecture/écriture.
 L'événement habituellement utilisé pour TextBox est TextChanged
qui signale que l'utilisateur à modifié le champ de saisie.

224
Étiquettes Label et boîtes de saisie TextBox

 Voici un exemple qui utilise l'événement TextChanged pour suivre les


évolutions d'un champ de saisie :.

225
Étiquettes Label et boîtes de saisie TextBox

Le code pertinent de cette application est celui des trois


gestionnaires d'événements:

private void cmdQuitter_Click(object sender, System.EventArgs e)


{
Application.Exit();
}
private void txtSaisie_TextChanged(object sender, System.EventArgs e)
{
lblControle.Text=txtSaisie.Text;
}
private void cmdEffacer_Click(object sender, System.EventArgs e)
{
txtSaisie.Text="";
}
226
Étiquettes Label et boîtes de saisie TextBox

 L'exemple suivant utilise un TextBox multilignes :

227
Étiquettes Label et boîtes de saisie TextBox

 Pour qu'un TextBox devienne multilignes on positionne les


propriétés suivantes du contrôle :
 Multiline=true pour accepter plusieurs lignes de texte
 ScrollBars=( None, Horizontal, Vertical, Both) pour demander à
ce que le contrôle ait des barres de défilement (Horizontal,
Vertical,Both) ou non (None)
 AcceptReturn=(True, False) si égal à true, la touche Entrée fera
passer à la ligne
 AcceptTab=(True, False) si égal à true, la touche Tab générera
une tabulation dans le texte

228
Étiquettes Label et boîtes de saisie TextBox

 Le code utile est celui qui traite le clic sur le bouton


Ajouter :
private void btnAjouter_Click(object sender, System.EventArgs e)
{
// ajout du contenu de txtAjout à celui de txtMultilignes
txtMultilignes.Text+=txtAjout.Text;
txtAjout.Text="";
}

229
listes déroulantes ComboBox

230
listes déroulantes ComboBox

 Un composant ComboBox est une liste déroulante doublée


d'une zone de saisie : l'utilisateur peut soit choisir un
élément dans (2) soit taper du texte dans (1).
 Il existe trois sortes de ComboBox fixées par la propriété
DropDownStyle :
 Simple liste non déroulante avec zone d'édition
 DropDown liste déroulante avec zone d'édition
 DropDownList liste déroulante sans zone d'édition
 Par défaut, le type d'un ComboBox est DropDown.

231
listes déroulantes ComboBox

 La classe ComboBox a un seul constructeur :


 new ComboBox() crée un combo vide
 Les éléments du ComboBox sont disponibles dans la
propriété Items :
 public ComboBox.ObjectCollection Items {get;}
 C'est une propriété indexée, Items[i] désignant l'élément i
du Combo.
 Elle est en lecture seule.

232
listes déroulantes ComboBox
 Soit C un combo et C.Items sa liste d'éléments. On a les propriétés
suivantes:
 C.Items.Count nombre d'éléments du combo
 C.Items[i] élément i du combo
 C.Add(object o) ajoute l'objet o en dernier élement du combo
 C.AddRange(object[] objets) ajoute un tableau d'objets en fin de combo
 C.Insert(int i, object o) ajoute l'objet o en position i du combo
 C.RemoveAt(int i) enlève l'élément i du combo
 C.Remove(object o) enlève l'objet o du combo
 C.Clear() supprime tous les éléments du combo
 C.IndexOf(object o) rend la position i de l'objet o dans le combo

 L'élément sélectionné dans le combo C est C.SelectedItem ou


C.Items[C.SelectedIndex] où C.SelectedIndex est le n°de l'élément
sélectionné, ce n° partant de zéro pour le premier élément. 233
listes déroulantes ComboBox

 Lors du choix d'un élément dans la liste déroulante se produit


l'événement SelectedIndexChanged qui peut être alors utilisé
pour être averti du changement de sélection dans le combo.
 Dans l'application suivante, nous utilisons cet événement pour
afficher l'élément qui a été sélectionné dans la liste.

234
listes déroulantes ComboBox

 Nous ne présentons que le code pertinent de la fenêtre.


 Dans le constructeur du formulaire nous remplissons le combo
public frmCombo()
{
// création formulaire
InitializeComponent();
// remplissage combo
}//constructeur

235
listes déroulantes ComboBox

 Nous traitons l'événement SelectedIndexChanged du combo


qui signale un nouvel élément sélectionné :
private void cmbNombres_SelectedIndexChanged(object sender,
System.EventArgs e)
{ // l'élément sélectionné à changé - on l'affiche
MessageBox.Show("Elément sélectionné : (" +
cmbNombres.SelectedItem +"," +
cmbNombres.SelectedIndex+")","Combo",Message
BoxButtons.OK, MessageBoxIcon.Information);
}

236
composant ListBox
 On se propose de construire l'interface suivante:

237
composant ListBox

 L'utilisateur tape du texte dans le champ 1. Il l'ajoute à la liste 1 avec le


bouton Ajouter (2). Le champ de saisie (1) est alors vidé et l'utilisateur
peut ajouter un nouvel élément.
 Il peut transférer des éléments d'une liste à l'autre en sélectionnant
l'élément à transférer dans l'une des listes et en choisissant le bouton de
transfert adéquat 5 ou 6. L'élément transféré est ajouté à la fin de la liste
de destination et enlevé de la liste source.
 Il peut double-cliquer sur un élément de la liste 1. Ce élément est alors
transféré dans la boîte de saisie pour modification et enlevé de la liste 1.

238
composant ListBox
 Les boutons sont allumés ou éteints selon les règles suivantes :
 le bouton Ajouter n'est allumé que s'il y a un texte non vide dans le
champ de saisie
 le bouton 5 de transfert de la liste 1 vers la liste 2 n'est allumé que s'il
y a un élément sélectionné dans la liste 1 le bouton 6 de transfert de
la liste 2 vers la liste 1 n'est allumé que s'il y a un élément sélectionné
dans la liste 2
 les boutons 7 et 8 d'effacement des listes 1 et 2 ne sont allumés que si
la liste à effacer contient des éléments.
 Dans les conditions précédentes, tous les boutons doivent être éteints lors
du démarrage de l'application.
 C'est la propriété Enabled des boutons qu'il faut alors positionner à false.
 On peut le faire au moment de la conception ce qui aura pour effet de
générer le code correspondant dans la méthode InitializeComponent ou
de le faire nous-mêmes dans le constructeur comme ci-dessous :
239
composant ListBox

public Form1()
{
// création initiale du formulaire
InitializeComponent();
// initialisations complémentaires
// on inhibe un certain nombre de boutons
btnAjouter.Enabled=false;
btn1TO2.Enabled=false;
btn2TO1.Enabled=false;
btnEffacer1.Enabled=false;
btnEffacer2.Enabled=false;
}

240
composant ListBox

L'état du bouton Ajouter est contrôlé par le contenu du champ de


saisie. C'est l'événement TextChanged qui nous permet de suivre les
changements de ce contenu :

private void txtSaisie_TextChanged(object sender,


System.EventArgs e) {
// le contenu de txtSaisie a changé
// le bouton Ajouter n'est allumé que si la saisie est non vide
btnAjouter.Enabled=txtSaisie.Text.Trim()!="";
}

241
composant ListBox

L'état des boutons de transfert dépend du fait qu'un élément a été


sélectionné ou non dans la liste qu'ils contrôlent :
private void listBox1_SelectedIndexChanged(object sender,
System.EventArgs e) {
// un élément a été sélectionné
// on allume le bouton de transfert 1 vers 2
btn1TO2.Enabled=true;
}
private void listBox2_SelectedIndexChanged(object sender,
System.EventArgs e) {
// un élément a été sélectionné
// on allume le bouton de transfert 2 vers 1
btn2TO1.Enabled=true;
}

242
composant ListBox

Le code associé au clic sur le bouton Ajouter est le suivant :

private void btnAjouter_Click(object sender, System.EventArgs e)


{
// ajout d'un nouvel élément à la liste 1
listBox1.Items.Add(txtSaisie.Text.Trim());
// raz de la saisie
txtSaisie.Text="";
// Liste 1 n'est pas vide
btnEffacer1.Enabled=true;
// retour du focus sur la boîte de saisie
txtSaisie.Focus();
}

243
composant ListBox
On notera la méthode Focus qui permet de mettre le "focus" sur un
contrôle du formulaire.
Le code associé au clic sur les boutons Effacer :

private void btnEffacer1_Click(object sender, System.EventArgs e)


{
// on efface la liste 1
listBox1.Items.Clear();
}
private void btnEffacer2_Click(object sender, System.EventArgs e)
{
// on efface la liste 2
listBox2.Items.Clear();
}

244
composant ListBox

Le code de transfert des éléments sélectionnés d'une liste vers l'autre :

private void btn1TO2_Click(object sender, System.EventArgs e)


{
// transfert de l'élément sélectionné dans Liste 1 vers Liste 2
transfert(listBox1,listBox2);
// boutons Effacer
btnEffacer2.Enabled=true;
btnEffacer1.Enabled=listBox1.Items.Count!=0;
// boutons de transfert
btn1TO2.Enabled=false;
btn2TO1.Enabled=false;
}

245
composant ListBox
private void btn2TO1_Click(object sender, System.EventArgs e)
{
// transfert de l'élément sélectionné dans Liste 2 vers Liste 1
transfert(listBox2,listBox1);
// boutons Effacer
btnEffacer1.Enabled=true;
btnEffacer2.Enabled=listBox2.Items.Count!=0;
// boutons de transfert
btn1TO2.Enabled=false;
btn2TO1.Enabled=false;
}
// transfert
private void transfert(ListBox l1, ListBox l2){
// transfert de l'élément sélectionné de la liste l1 vers la liste l2
// un élément sélectionné ?
if(l1.SelectedIndex==-1) return;
// ajout dans l2
l2.Items.Add(l1.SelectedItem);
// suppression dans l1
l1.Items.RemoveAt(l1.SelectedIndex);
} 246
composant ListBox

 Tout d'abord, on crée une méthode:


private void transfert(ListBox l1, ListBox l2){
qui transfère dans la liste l2 l'élément sélectionné dans la liste l1. Cela nous
permet d'avoir une seule méthode au lieu de deux pour transférer un élément
de listBox1 vers listBox2 ou de listBox2 vers listBox1. Avant de faire le
transfert, on s'assure qu'il y a bien un élément sélectionné dans la liste l1 :
// un élément sélectionné ?
if(l1.SelectedIndex==-1) return;
 La propriété SelectedIndex vaut -1 si aucun élément n'est actuellement
sélectionné.
 Dans les procédures: private void btnXTOY_Click(object sender,
System.EventArgs e), on opère le transfert de la liste X vers la liste Y et
on change l'état de certains boutons pour refléter le nouvel état des listes.
247
Les classes de dialogue standard
- Les classes de dialogue standard suivantes :

System.Windows.Forms.ColorDialog
System.Windows.Forms.FileDialog
System.Windows.Forms.FontDialog
System.Windows.Forms.OpenFileDialog
System.Windows.Forms.PageSetupDialog
System.Windows.Forms.PrintControllerWithStatusDialog
System.Windows.Forms.PrintDialog
System.Windows.Forms.PrintPreviewDialog
System.Windows.Forms.SaveFileDialog
248

Vous aimerez peut-être aussi