Introduction
La programmation orientée objet (POO), est un
paradigme de programmation
informatique élaboré par les Norvégiens Ole-
Johan Dahl et Kristen Nygaard au début des
années 1960 et poursuivi par les travaux de
l'Américain Alan Kay dans les années 1970.
• La POO utilise une approche différente de celle des
langages procéduraux.
• Comment certaines sociétés de l’industrie informatique
sont elles devenues si importantes et aussi vite ?
• Elles fabriquent en général de bonnes machines, vendues à
prix bas, dans une période où il existe une demande.
• Comment ont-elles pu construire tant de modèles aussi
rapidement, et comment ont-elles répondu aussi vite aux
changements que subit le marché de la micro-informatique ?
• Essentiellement, parce qu’elles ont sous-traité une
bonne partie de leurs travaux. Elles ont acheté des
éléments à des vendeurs réputés et se sont chargées
de l’assemblage des machines.(alimentations, disques
durs, cartes mères, etc.)
• Production rapide et réduction des coûts. Ces
constructeurs achetaient des «fonctionnalités
préconditionnées». (elles acquéraient quelque chose
qui possédait certaines propriétés (taille, poids, etc.) et
une certaine fonctionnalité (une sortie stabilisée, une
puissance électrique, etc.)
Programmation orientée objet
Les données membres sont des variables déclarées à l’intérieur de la classe mais à l'extérieur des
méthodes et sont en relation avec la nature de l’objet représenté par la classe.
class Nom_Classe
{
Type_Donnée1 Nom_Donnée1 ;
Type_Donnée2 Nom_Donnée2 ;
…
}
Exemple :
Un rectangle est défini par une largeur et une longueur. Ces informations doivent être représentées à
l’intérieur de la classe et sont dites données membre de la classe Rectangle
class Rectangle
{
double largeur ;
double longueur ;
}
Fonctions membres (méthodes) :
class Rectangle
{
double largeur ;
double longueur ;
double périmètre ()
{
double p ;
p=(largeur+longueur)*2 ;
return p ;
}
}
Accessibilité
class Rectangle
{
private double largeur ;
private double longueur ;
void setLargeur(double lar)
{
largeur =lar ;
}
void setLongueur(double lon)
{
longueur =lon ;
}
}
NB:
Les setters sont également appelés modificateurs
Remarque:
Une propriété en lecture seule doit disposer uniquement de getter
Les propriétés
Les propriétés sont utilisées pour rendre accessible les getters et setters via un nom commun.
Le principe est très simple. Au lieu de posséder deux méthodes (getter et setter) séparées, les deux sont
regroupées dans notre propriété au sein de deux blocs get et set. Cette dernière peut être appelée
comme une simple méthode et Visual Studio décidera automatiquement s’il doit appeler le getter ou le
setter.
Prenons directement un exemple :
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
Exercice
• Ecrire une classe Personne sachant que chaque
personne est identifiée par son nom, son
prénom, son sexe et son âge. Toutes ces données
doivent être déclarées privées.
• Ecrire les méthodes d ’accès à ces données
• Ecrire une méthode affiche() qui affiche ces
informations sous la forme suivante:
je suis……
J’ai……..
Je suis de sexe……
Instantiation d'une classe
Une fois une classe créée, il n'est pas possible de l’utiliser directement. Il faut créer des objets se basant
sur cette classe. Le processus de création d’un objet à partir d’une classe est appelé instantiation d’un
objet ou création d’une instance d’une classe. Un objet est donc l'instance d'une classe et il est possible
de créer autant d’objets souhaités basés sur une classe
Pour créer une instance d'une classe :
Nom_Classe Référence_Objet ;
Référence_Objet=new Nom_Classe () ;
Ou
Nom_Classe Référence_Objet =new Nom_Classe ();
Exemple :
Pour créer deux rectangle R1 et R2 à partir de la classe Rectangle :
Rectangle R1 ;
R1=new Rectangle () ;
Rectangle R2 ;
R2=new Rectangle () ;
Ou
Rectangle R1 =new Rectangle () ;
Rectangle R2 =new Rectangle () ;
Constructeur
C’est une méthode qui permet la création des
objets.
Il ya deux types de constructeur: par défaut et
par initialisation
Constructeur par défaut
Toute classe dispose d’une méthode spéciale appelée constructeur par défaut. Cette
méthode est appelée automatiquement chaque fois qu’on souhaite utiliser la classe
correspondante. Le constructeur par défaut porte le même nom que la classe, ne peut
spécifier de valeur de retour et ne doit pas être private.
Le constructeur par défaut sert à inclure certaines valeurs d'initialisation (valeurs par
défaut). A l'appel de la classe, ces valeurs sont automatiquement chargées.
S'il n'existe pas de valeurs à décrire ou de paramètres d'initialisation, la définition du
constructeur par défaut n’est pas nécessaire. La création des objets se fait
implicitement par le compilateur mais il est conseillé d'expliciter le constructeur par
défaut dans chaque classe.
Identificateur_Accès class Nom_Classe
{
Public nom_classe () //Constructeur par défaut
{
...
}
}
Constructeur par initialisation (par
assignation
Cette méthode spéciale permet d'appeler la classe et d'initialiser certaines ou toutes ses données membres. Comme le
constructeur par défaut, le constructeur par initialisation porte le même nom que la classe et ne doit être ni private, ni
void mais il reçoit en entrée des paramètres qui vont être affectés aux données membres et donc les différentes autres
méthodes vont utiliser ces valeurs pour effectuer les traitements.
Identificateur_Accès class Nom_Classe
{
Public nom_classe (type_Argument1 Arg1, Type_Argument2 Arg2,…)
{
Donnée_Membre1=Arg1 ;
Donnée_Membre2=Arg2 ;
…
}
…
}
Pour instancier une classe en utilisant le constructeur par initialisation :
Nom_Classe Référence_Objet =new Nom_Classe (param1,param2,…);
Remarque
Il est possible d’avoir plusieurs constructeurs d’initialisation dans la même classe. Le nom est le même mais le nombre
d’arguments à assigner sera différent.
Exemple :
class Rectangle
{
private double largeur ;
private double longueur ;
Public Rctangle()
{}
public Rectangle (double lar, double lon)
{
largeur=lar ;
longueur=lon ;
}
}
Remarque
• Si la classe ne contient pas de constructeurs,
un constructeur par défaut est créé
automatiquement; Mais dès que vous ajoutez
un constructeur par initialisation à votre
classe, si vous voulez utiliser le constructeur
par défaut, vous devez le créer même s’il est
vide
Constructeur par copie
Un constructeur qui crée un objet à partir d’un autre.
Exemple :
public Article(Article a)
{
this.refe = a.refe;
this.des = a.des;
this.pu = a.pu;
this.qte = a.qte;
Console.WriteLine("test de constructeur par
copie");
Destructeur
class MenuPrincipal
{
static void Main (string []args)
{
Rectangle R1=new Rectangle(20,30); // Construction rectangle par initialisation
Rectangle R2=new rectangle ();
Console.writeLine("Introduire la largeur du rectangle :");
double Lar=double.parse(console.readLine()) ;
console.writeLine("Introduire la longueur du rectangle :");
double Lon= double.parse(console.readLine()) ;
R2.setLargeur(Lar) ; //Appel du setter. La valeur saisie Lar sera affectée à largeur;
R2.setLongueur(Lon) ; //Appel du setter. La valeur saisie Lon sera affectée à longueur;
Console.writeLine("Informations sur le premier Rectangle :");
Console.writeLine ("Largeur="+R1.getLargeur());
Console.writeLine ("Longueur="+R1.getLongueur());
Console.writeLine ("Surface="+R1.surface());
Console.writeLine ("Périmètre="+R1.périmètre());
Console.writeLine ("Diagonale="+R1.diagonale());
Console.writeLine ("Informations sur le deuxième Rectangle :");
Console.writeLine ("Largeur="+R2.getLargeur());
Console.writeLine ("Longueur="+R2.getLongueur());
Console.writeLine ("Surface="+R2.surface());
Console.writeLine ("Périmètre="+R2.périmètre());
Console.writeLine ("Diagonale="+R2.diagonale());
}
}
Regroupement en paquets
(namespace) :
Il est possible de regrouper plusieurs définitions de classes
dans un groupe logique appelé namespace. Pour créer un
namespace, il suffit de commencer le fichier par l’instruction :
namespace Nom_namespace ;
Pour importer toutes les classes d’un namespace à l’intérieur
d’une classe :
using nom_ namespace ;
Remarque :
Toute classe sans indication de namespace appartient au
namespace par défaut.
L'héritage
Remarque :
C# n'accepte pas l'héritage multiple et donc les classes ne peuvent hériter que d’une seule classe à la
fois.
Pour appeler un constructeur de la classe mère on utilise le mot-clé base.
:base(); //Appel du constructeur par défaut
Ou
:base(argument1, argument2,…); // Appel d'un constructeur par initialisation
Redéfinition d'une méthode ou d’une propriété
Créer la classe EtudiantSecondeAnnée qui hérite de la classe Etudiant et qui possède la propriété suivante :
double noteProjet;
- La classe Etudiant
Implémenter les getters et les setters
Implémentez la méthode affichage qui permet d’afficher les informations de l’étudiant
Implémentez la méthode calculer la moyenne de 1ere année.
Implémentez deux constructeurs d’initialisation
La classe EtudiantSecondeAnnée
Implémenter les getters et les setters
Implémentez la méthode affichage qui permet d’afficher les informations de l’étudiant
Implémentez la méthode calculer la moyenne générale.
Implémentez deux constructeurs d’initialisation.
Les classes scellées
Méthodes abstraites
Une méthode abstraite n'est qu'une signature de
méthode sans corps de méthode. Elle n'est pas
directement exécutable et doit obligatoirement être
implantée dans une classe fille. Il s'agit de créer des
modèles génériques permettant de définir
ultérieurement des actions spécifiques.
Pour déclarer une méthode abstraite :
abstract Identificateur_Accès void|Type_retour
nom_méthode (argument1,argument2,…)
Classes abstraites
Une classe abstraite est une classe qui ne peut pas être instanciée et
seule une classe dérivée qui redéfinit obligatoirement toutes les
méthodes abstraites de cette classe mère peut être instanciée.
Remarques :
Si une classe contient au moins une méthode abstraite, elle doit être
déclarée comme classe abstraite.
Une classe abstraite peut contenir des méthodes non abstraites.
Une classe abstraite peut ne contenir aucune méthode abstraite
Pour déclarer une classe abstraite :
abstract public nom_classe
{…}
Exercice classe et méthode abstraite
Variables de classe
Il existe des situations où une variable déclarée dans une
classe doit garder la même valeur pour toutes les instances de
cette classe. Dans ce cas toute modification de l'attribut sera
reconnue par toutes les instances de la classe. Ces variables
sont dites variables de classe ou statiques.
Pour indiquer qu'un attribut est de classe :
Modificateur_accès static Type_Données nom_Variable ;
Les variables de classes ne dépendent pas des instances de
classes et donc elles sont accessibles sans avoir besoin
d'instancier la classe :
Nom_Classe.Nom_Variable_de_Classe
Méthode de classe
Une méthode de classe est une méthode dont les résultats et les
actions ne varient pas d'instance en instance.
Pour indiquer qu'une méthode est de classe :
Modificateur_accès static void|Type_Données
nom_Méthode(Argument1, Argument2,…)
Comme pour les variables de classe, pour utiliser une méthode de
classe :
Nom_Classe.Nom_Méthode_de_Classe(Argument1, Argument2,…)
Exemple
Pour utiliser la méthode sqrt qui appartient à la classe Math, on a pas
besoin d'instantier la classe Math parce qu'il s'agit d'une méthode
static et ainsi on écrit directement console.writeLine(Math.sqrt(9)).
Exercice
Ecrivez une classe Livre avec les attributs suivants: titre, auteur, prix,
annee.
La classe Livre doit disposer des constructeurs suivants :
Livre(), Livre(titre), Livre(titre, auteur), Livre(titre, auteur, prix),
Livre(titre, auteur, prix, annee), Livre(Livre).
La classe Livre doit contenir des accesseurs et mutateurs pour les
différents attributs.
La classe livre doit aussi contenir une méthode afficher() pour afficher
les attributs des livres. Une méthode compter() pour avoir le nombre
des instances créées et une méthode type() qui va prendre 1 si le
prix de livre <100 et la valeur 2 si le 100<=prix< =500 et 3 si
500<prix.
Ecrivez aussi une classe de testLivre afin de tester la classe Livre
Gestion des exceptions
Introduction
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.
L’instruction Try Catch permet de traiter les erreurs qui
peuvent se produire dans un bloc d’instruction
try
{….//Bloc d’instruction. En cas d’erreur le bloc catch le plus
adapté traitera l’erreur
}
catch (….)
{….}
catch(….)
{… }
finaly
{Code à exécuter dans tous les cas }
• Chaque bloc Catch permet de traiter une
catégorie d’exception.
• Les blocs Catch ne seront exécutés que s’il y a
une erreur dans le bloc d’instructions.
• Le bloc finaly est toujours exécuté qu’il y ait
ou qu’il n’y ait pas d’erreur. (Bloc facultatif)
Les exceptions personnalisées
On reprend l’exemple de la classe Personne
class Personne
{
private string nom;
private string prenom;
private int age;
public Personne()
{
nbPersonnes++;
}
public Personne(string nom,string prenom, int age)
{
this.nom = nom;
this.prenom = prenom;
this.Age = age;
nbPersonnes++;
}
}
public Personne(Personne p)
{
nom = p.Nom;
prenom = p.Prenom;
Age = p.Age;
nbPersonnes++;
}
}
public string Prenom
{
get { return this.prenom; }
set { this.prenom = value; }
}
public static int NbPersonnes
{
get { return nbPersonnes; }
}
class ErreurAgeException:Exception
{
public ErreurAgeException()
{
Console.WriteLine("Erreur: Age négatif");
}
}
Il faut par la suite indiquer là où l’exception doit être levée en utilisant le mot clé throw. Dans notre cas,
une exception de type ErreurAgeException doit être levée au niveau du constructeur de la classe
personne (si l’utilisateur essaye de créer une personne avec un âge négatif) ou au niveau du setter de
l’attribut âge (si l’utilisateur essaye d’attribuer un âge négatif à une personne)
Console.WriteLine("donner l'age");
p.Age = int.Parse(Console.ReadLine());
p.afficher();
Console.Read();
}
Console.WriteLine("donner l'age");
try
{
p.Age = int.Parse(Console.ReadLine());
}
catch (ErreurAgeException e)
{
Console.WriteLine(e.Message);
}
p.afficher();
Console.Read();
}
Exercices
Exercice 1 :
Ecrire un programme C# qui permet de contrôler la saisie d’une note entre 0
et 20.
Exercice 2 :
Ecrire la méthode int moyenne(string[] listeDeNombres) dans la classe
Traitement qui prend en argument un tableau de chaînes de caractères. On
veut que toutes les chaînes qui ne comprennent pas des nombres entiers
soient éliminées du calcul et ne soient pas prises en compte pour calculer la
moyenne (on ne divise donc pas par listeDeNombres.length, mais par le
nombre de nombres entiers contenus dans ce tableau).
Exercice 3:
On veut maintenant que la méthode moyenne vue à l'exercice précédent lève
une exception de type TableauIncorrect si le tableau listeDeNombres passé en
argument de la méthode comprend des valeurs 'null'.
Ecrire la classe d'exception TableauIncorrect et modifier la méthode moyenne
pour qu'elle lève cette exception si nécessaire.
Les tableaux
Tableaux unidimentionnels :
on déclare un tableau à une seule dimension:
type[] nom = new type[capacité];
un tableau ne peut contenir que des éléments de même type.
Exemple1 : si vous voulez que votre tableau puisse stocker 20 valeurs :
int[] tableau = new int[20];
Déclaration et initialisation d’un tableau:
Exemple2: int[] tableau = new int[5] { 1, 5, 2, 1, 3 };
Pour accéder à un élément d'un tableau, la syntaxe est la suivante :
tableau[index] = valeur;
Exemple de tableau unidimentionnel
Console.Read();
Les tableaux multi-dimensionnels
Console.Read();
Tableaux d'objets
cdLibrary[0].Album = "See";
cdLibrary[0].Artist = "The Sharp Band";
}
}
La classe Array
Cette classe fournit plusieurs méthodes utiles permettant la manipulation d’un tableau, telles que Sort
et Reverse
Exemple:
public static void Main(string []args)
{
// Créer un tableau de string de taille 5
string[] Noms = new string[5];
// Lire les noms de 5 employés
System.Console.WriteLine("Entrer les noms de 5 emplyés:");
for (int i = 0; i < Noms.Length; i++)
{
Noms[i] = Console.ReadLine();
}
// Afficher les éléments du tableau saisi
Console.WriteLine("\nle tableau siasi:");
foreach (string nom in Noms)
{
Console.Write("{0} ", nom);
}
// Inverser le tableau
Array.Reverse(Noms);
// Afficher le tableau inversé
Console.WriteLine("\n\nLe tableau dans l’ordre inverse:");
foreach (string nom in Noms)
{
Console.Write("{0} ", nom);
}
// Trier le tableau
Array.Sort(Noms);
// Afficher le tableau trié
Console.WriteLine("\n\nLe tableau trié:");
foreach (string nom in Noms)
{
Console.Write("{0} ", nom);
}
}
}
Il existe d’autres méthodes dont les plus utilisées sont dans cet exemple:
class Program
{
static void Main(string[] args)
{
Client[] t = new Client[3];
t[0] = new Client("Alami", "ali", 2, 16);
t[1] = new Client("Alami", "fati", 2, 16);
t[2] = new Client("salmi", "ahmed", 4, 17);
ht.Add(1, "said");
ht.Add(2, "nabil");
ht.Add(3, "ikram");
ht.Add(4, "oussama");
foreach (DictionaryEntry myEntry in ht)
{
Console.WriteLine("Key: " + myEntry.Key + " valeur: " +
myEntry.Value);
}
Les Dictionary<TKey,TValue>
les membres d’une énumération peuvent également être appelés avec leur numéro:
Exemple :
class Program
{
enum Jours { lun, mar, mer, jeu, ven, sam, dim };
static void Main(string[] args)
{
Jours jourDeStage;
jourDeStage = (Jours)0;
Console.WriteLine(jourDeStage);
Console.ReadLine();
}
}
(Jours)0 équivaut à lundi, (Jours)1 équivaut à mardi etc.
Dernière remarque
on peut forcer l’attribution d’un numéro à un membre
Dans l’exemple suivant nous allons attribuer la valeur 1 à lundi, au lieu de 0, sa valeur
par défaut :
Exemple :
class Program
{
enum Jours { lun=1, mar, mer, jeu, ven, sam, dim };
static void Main(string[] args)
{
Jours jourDeStage;
jourDeStage = (Jours)3; //équivaut donc à mercredi.
Console.WriteLine(jourDeStage);
Console.ReadLine();
}
}
Les structures
Déclaration et initialisation
Nous allons prendre l’exemple d’un coureur, un coureur a un
nom, un prénom ainsi qu’un numéro de dossard. Nous allons
dons créer la structure « Coureur » qui va contenir ses
champs. Nous déclarons la structure en dehors du main mais
nous déclarons les différents champs en « public » afin que
ceux-ci soient accessibles dans le main.
La sérialisation
La sérialisation est le processus de conversion d'un objet en un flux d'octets.
Elle permet d’enregistrer l’état d’un objet pour pouvoir le recréer
ultérieurement après. Le processus inverse est appelé dé-sérialisation.
Il existe différents types de sérialisation :
Sérialisation binaire : Utilise le codage binaire pour stocker des données
Sérialisation XML : Sérialise un objet en un flux XML (XML est un format de
stockage et de structuration des données)
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
….
Stream S = File.Open("chemin_Fichier",
FileMode.Create);
BinaryFormatter BF = new BinaryFormatter();
BF.Serialize(S, Objet_A_sérialiser);
S.Close();
Sérialisation XML
using System.Xml.Serialization;
using System.IO;
….
Stream S = File.Open("xx.xml",FileMode.Create);
XmlSerializer X = new
XmlSerializer(ObjetASerialiser.GetType());
X.Serialize(S, ObjetASerialiser);
S.Close();
Dé-Sérialisation binaire
using System.Runtime.Serialization;
using
System.Runtime.Serialization.Formatters.Binary;
using System.IO;
….
Stream S = File.Open("chemin_Fichier ",
FileMode.Open);
BinaryFormatter BF = new BinaryFormatter();
Object A = BF.Deserialize(S);
S.Close();
Dé-Sérialisation XML
using System.Xml.Serialization;
using System.IO;
….
Stream S = File.Open("chemin_Fichier ",
FileMode.Open);
XmlSerializer X = new
XmlSerializer(ObjetASerialiser.GetType());
Object A = X.Deserialize(S);
S.Close();
REGEX
if (m.Success)
{
MessageBox.Show("existe");
MessageBox.Show(m.Index.ToString());
MessageBox.Show(m.Value);}
else{
MessageBox.Show("n'existe pas");
}
Cet exemple utilise l'objet matchCollection pour récupérer des informations
sur l'ensemble des éléments trouvés qui respectent modèle trouvé
Regex rx = new Regex(TextBox2.Text);
String s= TextBox1.Text;
//Le modèle peut se trouver plusieurs fois, on utilise une collection
MatchCollection MCol = rx.Matches(s);
MessageBox.Show("Nombre de modèles trouvés : " +
MCol.Count.ToString());
foreach(Match m in MCol)
{
MessageBox.Show("index :" +
m.Index.ToString()+Environment.NewLine+ "Valeur :" + m.Value.ToString());
}