Vous êtes sur la page 1sur 111

Programmation 

réseau en C#

Alain Casali
alain.casali@univmed.fr
C# c’est quoi ?
• Langage de programmation créé en 2002 (1° beta en
2000)
• Basé sur le framework .Net de Microsoft
• Un peu de C++ et de Java
• Facilités de développement grâce aux briques
logicielles
C# Comment ça marche ?
• Basé sur .Net Framework

Programme C# Programme Java

.Net Framework Machine virtuelle Java

Système d’exploitation
Différences (apports) par rapport au C++
• Orientation objet prononcée (tout dérive de la classe
object),
• Unicode comme code des caractères,
• Libération automatique de la mémoire,
• « fin » des pointeurs,
• Remplacement des pointeurs par des références,
• Passage des arguments par référence et non plus pas adresse,
• Nouvelle boucle (foreach),
• Disparition de l’héritage multiple au profit d’interface,
• Langage intropsectif.
Qui utilise C# ?
• Microsoft avec l’architecture .NET
• Linux, Mac OS X et Solaris grâce à Novel qui participe 
activement au projet Open Source Mono 
(http://www.mono‐project.com/). 
Beaucoup d’applications Gnome sont développées en C# 
grâce à GTK #
Les programmes développés grâce à C# sont
«portables» sur ces plateformes sans recompilation
!
• Actuellement Mono 2.0 (prise en charge
complète de .Net Framework 2.0 plus
quelques fonctions de .Net 3.5).
Question performances, ça donne quoi ?

Source : http://shootout.alioth.debian.org/u32/benchmark.php?test=all&lang=all
Organisation du cours et des TPs
• 4 séances de cours
• 6 séances de TPs
– 2 séances prises en main de C#
– 1 séance et ½ : client réseau
– 2 séance et ½ : serveur réseau
• Test : 
– ½ h : contrôle de connaissance
– 2h : test « classique » (mise en pratique des connaissances 
acquises)
• 1 avant projet
Plan du cours
1. Initiation à C#
2. Programmation réseau « de base » en C#
3. Programmation réseau « avancée» en C#
Partie 1 : Initiation à C#
Types primitifs
• Orientation objet prononcée ⇨ tous les types 
primitifs sont définis dans des classes 
• Chaque classe contient des données membres 
et des fonctions membres qui lui sont 
spécifiques
Les entiers (1)
Type Classe associé Commentaire
byte System.Byte Codé sur 1 octet, Type non signé 
0 ‐> 255
sbyte System.SByte Codé sur 1 octet, Type signé
‐128 ‐> 127
short System.Int16 Codé sur 2 octets, Type signé
‐215 ‐> 215‐1
ushort System.UInt16 Codé sur 2 octets, Type non signé
0 ‐> 216‐1
int System.Int32 Codé sur 4 octets, Type signé
‐231‐> 231‐1
uint System.UInt32 Codé sur 4 octets, Type non signé
0 ‐> 232‐1
long System.Int64 Codé sur 8 octets, Type signé
‐263 ‐> 263‐1
ulong System.UInt64 Codé sur 8 octets, Type non signé
0 ‐> 264‐1
Les entiers (2)
• int i = 3;
• Si un entier commence par ‘0x’ ou par ‘0X’, alors il 
est codé à l’aide d’une représentation hexadécimale.
• Si un entier se termine par la lettre ‘l’ ou ‘L’, alors 
c’est un entier long. Attention de le pas confondre la 
lettre ‘l’ avec le chiffre ‘1’.
long i = 3l;
• la représentation octale à disparue en C#
Les booléens
Type Classe associé Commentaire
bool System.Boolean Ne prend que pour valeur true
ou false. 
Attention, pas de 0 ou de 1 
comme en C++

bool MonBool = true;


Les réels
Type Classe associé Commentaire
float System.Single Réel code sur 32 bits
double System.Double Réel code sur 64 bits
decimal System.Decimal Réel code sur 128 bits

• Les variables peuvent contenir des valeurs 
« classiques », mais dans ce cas le séparateur entre la 
partie entière et la partie décimale est le caractère ‘.’ ou 
sous forme scientifique. Dans ce cas, c’est la lettre ‘e’ ou 
‘E’ qui représente l’exposant (toujours une puissance de 
10).
float Pi = 3.14f;
Les caractères
Type Classe associé Commentaire
char System.Char Codé sur 2 octets
En C#, on perd la 
compatibilité entre les byte
et les char du C++, l’un étant 
codé sur 2 octet, l’autre sur 
un seul ! 
On utilise le système Unicode

char CarCou = 'a';


Méthodes sur les caractères
• Les principales méthodes sur les caractères sont 
les suivantes :
– bool IsLower (char)
Remarque : les lettres accentuées font partie des 
minuscules.
– bool IsUpper(char)
– bool IsDigit (char)
– bool IsLetter (char)
– bool IsPonctuation (char)
– char ToLower(char)
– char ToUpper (char)
Les chaines de caractères
Type Classe associé Commentaire
string System.String

string ChaineCou = "abC";


Schéma de choix
• Ce sont les mêmes qu’en C++ :
if (Condition) {
bloc1;
}
else {
bloc2;
}
• Attention :
bool test = true;
if (1 == test) … // L'opérateur '==' ne
peut pas être appliqué aux opérandes de
type 'int' et 'bool'
• le switch peut s’appliquer sur les chaines de caractères
Boucles
ce sont les mêmes qu’en C++
1. for([init]; [condition]; [incrémentation])
{
bloc;
}
2. while (condition) attention : l’instruction while(1)
{ n’est pas valide en C#!!
bloc;
}
3. do
{
bloc;
}
while (condition)
Conversion Type Base*→ Type Base*
• Type Base* = type primitif \ string
• Utilisation d’une des méthodes statiques de la classe 
Convert :
float Pi = 3.14f;
int ValEnt = Convert.ToInt32(Pi);
• Utilisation du transtypage :
int ValEnt = (int) Pi;
Nb: lorsque le compilateur rencontre le transtypage, il 
appelle Convert.ToInt32()
La classe Convert contient d’autres méthodes :
ToSingle(), ToBoolean(), ToByte(), …
Conversion Type Base*→ String
• Chaque type de base contient une méthode 
ToString() qui transforme le contenu de la 
variable en la chaine de caractère associée.
int i = 4;
string chaine = i.ToString();
bool Test = true;
chaine = Test.ToString();
//chaine vaut « true »
Conversion String → Type Base*
La plupart des types de base contiennent une méthode 
Parse() qui permet de convertir une chaine de caractère 
en son type de base associé (à condition que la chaine soit 
correctement formatée).
string chaine = "1,3";
float i = Single.Parse(chaine);
float j = 1.2f;
chaine = "1.2f";
j = Single.Parse(chaine); //marche pas(2)
chaine = "22";
int k = Int32.Parse(chaine);
NB: Aucun contrôle d’erreur n’est effectué
Affichage écran (1)
Appel d’une des procédures  void
Console.Write(string)
Console.WriteLine(string)
Console.Write("valeur de j : " + j);
Ce qui est fait :
1. Transtypage de j en une chaine de caractères,
2. Concaténation des 2 chaines avec l’opérateur +,
3. Affichage de la chaine résultante
Affichage écran (2)
On veut afficher à l’écran la chaine :
Valeur de i : 2,22; valeur de j : 3,14
3 solutions 
1. Console.Write("Valeur de i : " + i + ";");
Console.WriteLine(" valeur de j : " + j );
2. Console.WriteLine("valeur de i : " + i + ";
valeur de j : " + j );
3. Console.WriteLine("Valeur de i : {0} ; valeur de
j {1} ", i, j );
Saisie clavier
Appel d’une des fonctions 
int Console.Read()
string Console.ReadLine()
Read() ne lit qu’un caractère, alors que
ReadLine() lit tous les caractères jusqu’à appuis 
de la touche Entrée. On peut lire au maximum 
Int32.MaxValue caractères (0x7FFFFFFF). 
string Chaine = Console.ReadLine();
Saisie clavier & buffer (2)
Read() ne lit qu’un caractère.
int a = Console.Read();
Console.WriteLine(Convert.ToChar(a));
Console.ReadLine();
le caractère <cr> est toujours présent dans le buffer 
de lecture⇨ pas besoin de caractères dans 
ReadLine ()
Saisie clavier & buffer (3)
int a;
do
{
a = Console.Read();
Console.WriteLine(Convert.ToChar(a));
}
while (' ' != Convert.ToChar(a));
string ch = Console.ReadLine();
Console.WriteLine(ch);

Entrée : la jolie chaine <cr>
Sortie :  ⇨ on évite d’utiliser Read()
l
a
jolie chaine
Les tableaux (1)
• Déclaration
type[] NomDuTableau;
NomDuTableau fait référence vers un tableau de 
type à une dimension. Ce tableau n’est pas encore 
alloué et sa taille n’est pas fixée.
• Allocation
NomDuTableau = new type [Taille];
• Exemple avec un tableau de 10 entiers
– C++ : int TabInt [10];
– C# : int[] TabInt = new int [10];
• Avec plusieurs dimensions
int [,] MatriceInt = new int [2,2];
Les tableaux (2)
• Accès à la i° case se fait grâce à la notation entre [] 
(comme en C++)
• Initialisation du tableau
– Une case après l’autre
TabInt[0] = 0;
TabInt[1] = 1; …
– Utilisation d’un type énumératif
int[] TabInt = {0, 1, …}
Dans ce cas, on ne précise pas la taille du tableau créé.
• Suppression : rien à faire, l’objet est 
automatiquement supprimé dès que la variable n’a 
plus de portée. On peut aussi l’affecter à null.
Parcours d’un tableau (1)
type[] Tab = new type [Taille];
On veut parcourir le tableau Tab et afficher chacun de ses 
éléments. C’est une donnée membre
1. utilisation de la boucle for
for (int i = 0; i < Tab.Length; ++i)
Console.Write(Tab[i] + " ");
2. utilisation d’un énumérateur
IEnumerator ie = Tab.GetEnumerator();
while (ie.MoveNext())
Console.Write(ie.Current + " ");
Parcours d’un tableau (2)
3. Utilisation d’une boucle foreach
foreach (type Var in Tab)
Console.Write(Var + " ");
Cette méthode appelle de façon transparente la 
méthode avec un énumérateur. Cependant, elle est 
plus simple à utiliser.
Remarque : la variable de parcours ne peut pas être 
présente dans le membre de gauche d’une 
affectation.
Introspection (1)
• En C#, une variable est capable de connaitre son 
type, c’est l’introspection. On peut obtenir ce type 
comme suit pour une variable var : 
var.GetType().Name Retourne un string

• Soit le tableau suivant 
object[] TabObj = new object[3];
TabObj[0] = 1; Int32
TabObj[1] = "bla"; String
TabObj[2] = 1.2f; Single
On veut afficher le type de chaque variable du tableau :
foreach (object obj in TabObj)
Console.WriteLine(obj.GetType().Name);
Introspection (2)
• Tester le type d’un objet
1. if (obj is type)
2. if ("type" == obj.GetType().Name)
• On veut ajouter la valeur 1 à chaque objet de type 
numérique
for (int i = 0; i < TabObj.Length; ++i)
{
if ( (TabObj[i] is Single) ||
(TabObj[i] is Int32))
TabObj[i] += 1;
} Erreur ֲL'opérateur '+=' ne peut pas être appliqué 
aux opérandes de type 'object' et 'int‘
Introspection (3)
Pour que cela marche, on est obligé de transtyper 
l’objet courant dans son type, puis de lui ajouter 1.

if (TabObj[i] is Single)
TabObj[i] = (Single) TabObj[i] + 1 ;
else if (TabObj[i] is Int32)
TabObj[i] = (Int32)TabObj[i] + 1;
Méthodes et données sur les tableaux
• Tous les tableaux dérivent de la classe array.
• Deux données membres 
1. Length : nb total d’éléments
Console.Write(TabInt.Length); //10
2. Rank : nb de dimensions
Console.Write(TabInt.Rank); //1
• Méthodes de la classe array
– void Clear (Array Tab, int pos, int nb)
Remet à 0 nb éléments du tableau Tab à partir de la 
position pos (ou à des chaines vides)
Array.Clear(TabInt, 0, TabInt.Length);
Méthodes sur les tableaux (2)
• Recherche d’éléments
int IndexOf (Array tab, object o)
int IndexOf (Array tab, object o, int posdeb)
int IndexOf (Array tab, object o, int posdeb,
int posfin)
Recherche de la première occurrence de l’élément o
dans le tableau tab entre les positions posdeb et 
posfin. Renvoie ‐1 si l’élément est absent.
int n = Array.IndexOf(TabInt, 1, 0); //1
n = Array.IndexOf(TabInt, 1, 2); //-1
Méthodes sur les tableaux (3)
• tri
void Sort (Array tab)
trie le tableau tab
Array.Sort(TabInt);
• inversion
void Reverse (Array tab)
inverse la séquence des éléments dans le tableau 
tab
Array.Reverse(TabInt); // 9, 8, 7,…
Méthodes sur les tableaux (4)
• Copie de tableau
void CopyTo (Array Tab, int pos)
copie les éléments du tableau vers le nouveau 
tableau Tab (de taille supérieur ou égale) et à partir 
de la position pos .
int[] TabCopy = new int[TabInt.Length];
TabInt.CopyTo(TabCopy, 0); // 0, 1, 2, …

int[] TabCopy = new int[TabInt.Length + 1];


TabInt.CopyTo(TabCopy, 1); // 0, 0, 1, 2, …

int[] TabCopy = new int[TabInt.Length];


TabInt.CopyTo(TabCopy, 1); // marche pas!!
Méthodes sur les chaines de 
caractères (1)
• les chaines de caractères (string) peuvent être vues comme des tableaux de 
caractères ⇨
– les variables disposent d’une donnée membre Length qui fournit la
taille de la chaine
– les fonctions membres des tableaux IndexOf existent, à la fois pour
des caractères uniques, et pour des chaines de caractères.
int IndexOf (String tab)
int IndexOf (String tab, int posdeb)
int IndexOf (String tab, int posdeb,
int sur_combien_de_car)
string chaine = "lalalilala";
string sschaine = "la";
int n = chaine.IndexOf(sschaine,5, chaine.Length-5);
Méthodes sur les chaines de 
caractères (2)
• inclusion
bool Contains (string)
if (chaine.Contains(sschaine)) …
• comparaison de chaines de caractères
1. int Compare ( string strA, string strB [, bool
ignoreCase] )
ignoreCase : booléen pour savoir si la case est
importante ou pas.
Valeurs de retour :
0 si strA vaut strB
<0 si strA < strB
>0 si strA > strB
int k = String.Compare(chaine, sschaine); //1
Méthodes sur les chaines de 
caractères (3)
2. bool Equals (string)
if (chaine.Equals(sschaine)) …
3. tester l’égalité entre les 2 chaines
if (strA == strB) …
– efficacité des 3 méthodes proposées :
la méthode 2 est (presque 2 fois) plus rapide que la 
méthode 3 qui est (presque 2 fois) plus rapide que la 
méthode 1.
• string ToUpper() ⇨ mise en majuscule de la chaine
string ToLower() ⇨ mise en minuscule de la chaine
string Trim() ⇨ supprime les espaces blancs en
début et en fin de chaine
Méthodes sur les chaines de 
caractères (4)
• découper une ligne
string[] Split (char[])
string banana = "ice cream";
string[] Dessert = banana.Split(new char[] { ' ' });
foreach (string plate in Dessert)
Console.WriteLine(str);
//ice
//cream

string[] Dessert = banana.Split(new char[] {'e', ' '});


foreach (string plate in Dessert)
Console.WriteLine(str);
//ic
//
//cr
//am
premier programme en C#
• plus d’« include » ni de .h
• forte utilisation des espaces de noms
• Main(string[] args) et non 
main(int argc, char** argv)
• args[0] n’est pas le nom du programme, 
mais bien le 1° argument !
Procédures et fonctions (1)
• Procédure
void NomProc (type1 Var1, type2 Var2, …) {
corps;
}
• Fonction
typeRetour NomFct (type1 Var1, type2 Var2,
…){
corps;
return typeRetour;
}
• Dans ces 2 cas, la valeur des variables ne change pas avant et 
après l’appel de la procédure (fonction).
Procédures et fonctions (2)
int Inc(int i)
{
return ++i;
}
static void Main(string[] args)
{
int i = 1;
int j = Inc(i);
Console.WriteLine(i + " " + j); // 1 2
Console.ReadLine();
}
Procédures et fonctions (3)
Tous les arguments des fonctions et procédures sont de type IN 
(passage des paramètres par valeurs),  si on veut les modifier, il faut 
préfixer le type par ref (passage par référence) dans la fonction 
et dans son appel. Le paramètre est alors de type IN OUT.

int Inc(ref int i)


{
return ++i;
}

int i = 1;
int j = Inc(ref i);
Console.WriteLine(i + " " + j); // 2 2
Procédures et fonctions (4)
Pour avoir un paramètre de type OUT, il faut préfixer le type par le mot 
clé out (passage par référence) dans la fonction et son appel.

int Inc(out int i)


{
i = 1; Attention : initialisation obligatoire de i dans la fonction
• Utilisation du paramètre out non assigné 'i‘
return i++; • Le paramètre de sortie 'i' doit être assigné avant que le 
} contrôle quitte la méthode actuelle


int i = 4;
int j = Inc(out i);
Console.WriteLine(i + " " + j); // 2 1
Les classes (1)
class NomDeClasse {
protected type _nom;

protected type f(…)


}
Les données membres et méthodes peuvent être de 3 types :
1. private : accessible par les seules méthodes internes de 
la classe
2. protected : accessible par les seules méthodes internes 
de la classe ou d'un objet dérivé
3. public : accessible par toute fonction définie ou non au 
sein de la classe
Les classes (2)
class CPersonne
{
public string _nom;
public string _prenom;
public int _age;

public void EcritConsole()


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

public void Initialisation(string N, string P, int A)


{
this._nom = N; Vu qu’il n’y a pas de conflit entre le nom des
this._prenom = P; variables de la fonction Initialisation et les
this._age = A; données membres de la classe CPersonne, le
}
} // CPersonne mot clé this n’est pas obligatoire.
Les classes (3)
• Création d’un objet
CPersonne P1;
– P1 est une référence à un objet de type CPersonne. Cet objet n'existe 
pas encore et donc P1 n'est pas initialisé.

• Utilisation des méthodes associées
P1.Initialisation("Casali","alain",30);
– Utilisation d'une variable locale non assignée
'P1'
P1.EcritConsole();
Les classes (3)
• Création d’un objet
CPersonne P1 = null;
– La variable P1 ne fait référence à aucun objet

• Utilisation des méthodes associées
P1.Initialisation("Casali","alain",30);
– on fait appel à la méthode Initialisation de l'objet référencé 
par P1. Or cet objet n'existe pas encore et le compilateur ne signalera 
l'erreur mais le programme plantera.
P1.EcritConsole();
Les classes (3)
• Création d’un objet
CPersonne P1 = new CPersonne();

• Utilisation des méthodes associées
P1.Initialisation("Casali","alain",30);
P1.EcritConsole();
Les classes (4)
Constructeurs
Pour créer puis instancier un objet, on est obligé de :
1. CPersonne P1 = new CPersonne();
2. P1.Initialisation("Casali","alain",30);

• On ajoute donc un constructeur à la classe CPersonne :
public CPersonne(string N, string P, int A)
{
this.Initialisation(N, P, A);
}
• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain",
30);
Les classes (4)
• Ajout d’un deuxième constructeur
public CPersonne(CPersonne P)
{
_nom = P._nom;
_prenom = P._prenom;
_age = P._age;
}
• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain", 30);
CPersonne P2 = new CPersonne(P1);
CPersonne P3 = P1;
• Même si les objets P1 et P2 contiennent la même information, ils ne sont 
pas égaux (ce sont des objets différents et on n’a pas surchargé l’opérateur 
==). Par contre les objets P3 et P1 sont bien égaux !!
Les classes (5)
Passage par référence
Dans l’exemple précédent, les objets P1 et P3 font référence à la même zone 
objet / mémoire. C’est pour cela qu’on peut tester l’égalité sans surcharge 
de l’opérateur ==. Par contre, toute modification d’un des deux objets 
entraine la modification de l’autre !!! 
CPersonne P1 = new CPersonne("Casali", "alain", 30);
CPersonne P2 = new CPersonne(P1);
CPersonne P3 = P1;
P1.EcritConsole(); //Casali, alain, 30
P2.EcritConsole(); //Casali, alain, 30
P3.EcritConsole(); //Casali, alain, 30
P1._prenom = "bob";
P1.EcritConsole(); //Casali, bob, 30
P2.EcritConsole(); //Casali, alain, 30
P3.EcritConsole(); //Casali, bob, 30
Les classes (6)
Accesseurs / Modifieurs
On veut lire / modifier des attributs privés ou protégés.
On suppose que l’attribut _prenom est de type protected.
• Accesseur
public string getPrenom() {
return _prenom;
}
• Modifieur
public void setPrenom(string P){
this._prenom = P;
}
• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain", 30);
Console.WriteLine(P1.getPrenom()); // alain
P1.setPrenom("bob");
P1.EcritConsole(); // Casali, bob, 30
Les classes (6)
On peut utiliser les propriétés pour faire la même chose :
public string prenom
{
get { return _prenom;} //lecture
set { _prenom = value; } //écriture
}
• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain",30);
Console.WriteLine(P1.prenom); // alain
P1.prenom = "bob";
P1.EcritConsole(); // Casali, bob, 30
Attention : une propriété ne peut pas avoir le même nom que l’attribut qu’elle 
« gère ». On a donc préfixé le nom des attributs de la classe par le caractère ‘_’.
Les classes (7)
Attributs et méthodes statiques
Un champ statique d’une classe :
• existe indépendamment des objets de la classe (même si aucun objet n’a été crée);
• est partagé par tous les objets de la classe;
• peut être initialisé et manipulé dans une méthode de la classe comme n’importe 
quel attribut.

• On veut compter le nombre de personnes que l’on crée
static public int _nbPersonne = 0;

• On modifie les constructeurs de la classe CPersonne pour prendre en compte le 
nouvel attribut.
public CPersonne(string N, string P, int A)
{
this.Initialisation(N, P, A);
++_nbPersonne;
}
Les classes (7)
On accède à l’attribut static d’une classe par la notation préfixée 
classe.attribut

Console.WriteLine(CPersonne._nbPersonne);
// 0
CPersonne P1 = new CPersonne("Casali", "alain", 30);
CPersonne P2 = new CPersonne(P1);
Console.WriteLine(CPersonne._nbPersonne);
// 2
CPersonne P3 = P2;
Console.WriteLine(CPersonne._nbPersonne);
//2 P3 n’est pas un objet, c’est juste une référence vers un objet !
Attention : contrairement au C++ un objet ne peut accéder à aucun attribut 
static d’une classe (ex : P1._nbPersonne).
Les classes (7)
Les méthodes (non) statiques doivent respecter les règles suivantes :
• Une méthode statique n’a accès qu’aux attributs statique de la classe;
• Une méthode statique peut appeler une autre méthode statique mais ne peut pas 
appeler une méthode non statique;
• Une méthode non statique a accès à tous les attributs de la classe (statiques ou 
non).

• On va associé une propriété à la variable statique _nbPersonne (qui est privée 
dans l’exemple)
static public int nbPersonne
{
get { return _nbPersonne; }
}

• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain", 30);
CPersonne P2 = new CPersonne(P1);
Console.WriteLine(CPersonne.nbPersonne); //2
Les classes (8)
Passage d’objet à une fonction
Contrairement à ce que l’on pourrait penser, les objets sont passés par référence dans 
des sous‐programmes et non par valeur (recopie) ! Seuls les types primitifs sont 
passés par valeurs dans les fonctions et procédures.
• On modifie le prénom d’une CPersonne dans une autre classe :
static public void Modifie(CPersonne P)
{
P.prenom = "bob";
}
• Dans le Main(), on écrit :
CPersonne P1 = new CPersonne("Casali", "alain", 30);
P1.EcritConsole();
// Casali, alain, 30
Modifie(P1);
P1.EcritConsole();
// Casali, bob, 30
Les classes (9)
Tableaux d’objets
Puisqu’on peut créer des tableaux de type primitifs, on peut créer des tableaux 
d’objets
En fait ce sont des tableaux de référence vers des objets
• Création d’un tableau de 3 personnes
CPersonne[] TabPers = new CPersonne[3];
Les 3 éléments du tableau sont initialisés avec valeur null : ils ne référencent 
aucun objet
• Initialisation des objets du tableau
TabPers[0] = new CPersonne("Casali", "alain", 30);
TabPers[1] = new CPersonne("Casali", "bill", 30);
TabPers[2] = TabPers[1];
CPersonne.Modifie(TabPers[1]);
foreach (CPersonne P1 in TabPers)
P1.EcritConsole();
// Casali, alain, 30
// Casali, bill, 30 →bob
// Casali, bill, 30 →bob
Les classes (10)
Héritage
On va créer la classe CPersonneS qui hérite de la classe Cpersonne.
L’attribut _sexe est ajouté.
Les constructeurs de la classe aussi.
class CPersonneS : CPersonne
{
protected char _sexe;
public CPersonneS(string Nom, string Prenom,
int age, char sexe) : base(Nom, Prenom, age)
{
Appel au constructeur de la classe CPersonne
this._sexe = sexe;
}
public CPersonneS(CPersonne P, char sexe) : base(P)
{
_sexe = sexe;
}
}
Attention : contrairement au C++, l’héritage multiple n’existe pas en C#
Les classes (10)
Polymorphisme
Tous objets d’une classe fille ont accès aux fonctions de sa 
classe mère (si les accès sont possibles, i.e. non privés)
• Dans le Main(), on écrit :
CPersonneS P1 = new CPersonneS ("Casali",
"alain", 30, 'M');
P1.EcritConsole(); // Casali, alain, 30
CPersonneS P2 = new CPersonneS(P1, ‘?');
P2.EcritConsole(); // Casali, alain, 30
Console.WriteLine(CPersonne.nbPersonne);
//2
Les classes (11)
Surcharge de fonctions / procédures
On veut écrire la fonction EcritConsole() pour la classe CPersonneS de 
façon à pouvoir afficher le sexe d’un individu.
• Dans la classe CPersonneS, la fonction EcritConsole() doit être précédée 
du mot clé new pour indiquer qu’on redéfini une nouvelle méthode pour la 
classe CPersonneS.
• 2 surcharges sont alors possibles :
1. On écrit tout 
public new void EcritConsole() {
Console.WriteLine (_nom + "," + _prenom + "," + _age
+ "," + _sexe);
}
2. On utilise la fonction EcritConsole() de la classe mère 
public new void EcritConsole() {
base.EcritConsole();
Console.WriteLine("," + _sexe);
}
Les classes (11)
• Dans le Main(), on écrit :
CPersonneS P1 = new CPersonneS ("Casali",
"alain", 30, 'M');
P1.EcritConsole(); // Casali, alain, 30, M
CPersonneS P2 = new CPersonneS(P1, ‘?');
P2.EcritConsole(); // Casali, alain, 30, ?
Les classes (12)
Fonctions virtuelles
• Soit le programme suivant : 
CPersonneS P1 = new CPersonneS ("Casali", "alain",
30, 'M');
P1.EcritConsole(); // Casali, alain, 30, M
CPersonne P2;
P2 = new CPersonneS(P1, '?');
P2.EcritConsole(); // Casali, alain, 30
• P2 a été déclaré de type CPersonne mais instancié comme une
CPersonneS. Lors de l’affichage, le programme considère que P2 est 
une CPersonne et  non une CPersonneS. Cette information ne 
peut être connue lors de la compilation mais seulement au cours de 
l’exécution du programme. Pour des raisons de performance, le 
compilateur ne gère pas le code permettant de faire le transtypage 
nécessaire.
• Pour résoudre ce problème, il faut utiliser des fonctions virtuelles.
Les classes (12)
Pour pouvoir tenir compte du véritable type de P2 au moment 
de l’affichage, il faut : 
1. Qualifier la fonction EcritConsole() de virtual
dans la classe de base (ici CPersonne);
public virtual void EcritConsole() {…}
2. Qualifier la fonction EcritConsole() de override
dans la classe dérivée (ici CPersonneS).
public override void EcritConsole() {…}
Remarque : on n’a plus besoin  d’utiliser le mot clé new pour 
la surcharge dans la classe fille.

En faisant ces modifications, l’affichage pour la variable P2 est 
bien Casali, Alain, 30, ?
Les classes (13)
Redéfinition d’un opérateur pour une classe
• Opérateur unaire : 
public static [type] operator NomOp (Classe variable1);
• Opérateur binaire :
public static [type] operator NomOp (Classe variable1,
type2 variable2);

• On va définir l’opérateur ++ qui ajoute 10 ans à une CPersonneS.
public static CPersonneS operator ++(CPersonneS P)
{
P._age += 10;
return P;
}
• Dans le Main(), on écrit :
CPersonneS P1 = new CPersonneS("Casali", "alain", 30,
'M');
++P1;
P1.EcritConsole(); // Casali, Alain, 40, M
Attention : les opérateurs == et != doivent être définis en même temps.
Les classes (14)
La classe object
Tous les objets C# dérivent de cette classe
Les méthodes de cette classe sont :
• public virtual bool Equals(object obj);
Détermine si deux instances de Object sont égales. 
• public virtual int GetHashCode();
Sert de fonction de hachage pour un type particulier. GetHashCode
est approprié à une utilisation dans des algorithmes de hachage et 
des structures de données telles qu'une table de hachage. 
• public Type GetType();
Obtient le Type de l'instance en cours. 
• public virtual string ToString();
Retourne un String qui représente l'Object en cours.
Les classes (14)
• Pour transformer un objet en un string afin de l’afficher à 
l’écran, il faut écrire :
public override string ToString() {
return _nom + "," + _prenom + "," +
_age + "," + _sexe;
}
• Pour comparer deux objets, il faut :
1. Redéfinir la méthode Equals de la classe Object;
2. Redéfinir les opérateurs == et != ;
3. Redéfinir la fonction GetHashCode() de Object
Les classes (14)
On veut comparer deux objets de type CPersonneS (même nom et même prénom).
1. public override bool Equals(object obj) {
CPersonneS P = (CPersonneS)obj;
return _nom == P._nom && _prenom == P._prenom;
}
2. public static bool operator ==(CPersonneS P1,
CPersonneS P2) {
return P1.Equals(P2);
}
3. public override int GetHashCode() {
return this.ToString().GetHashCode();
}
• Dans le Main(), on écrit :
CPersonneS P1 = new CPersonneS("Casali", "alain", 30,
'M');
CPersonneS P2 = new CPersonneS("Casali", "alain", 40,
‘?');
if (P1 == P2)
Console.WriteLine("égalité");
Les Exceptions
• La plupart des fonctions C# gèrent les erreurs 
aussi appelée exception.
• La classe mère qui gère les exceptions est la 
classe Exception.
• Comme en C++, la gestion des exceptions se fait 
sur le schéma 
try { code }
catch (Exception e)
{traitement de l’exception}
[finally {bloc}]
instruction suivante
Les Exceptions
Exemple dans le cas d’un débordement de tableau
try
{
CPersonneS[] TabPers = new CPersonneS[3];
TabPers[0] = new CPersonneS("casali", "alain", 30, 'M');
TabPers[10] = TabPers[0];

foreach (CPersonneS P in TabPers)


Console.WriteLine(P);
}
catch (Exception e)
{
Console.Write(e); Nom de l’exception levée
}
Le message affiché est le suivant : 
System.IndexOutOfRangeException: L'index se trouve en dehors des limites du 
tableau.   à cours_classe.Program.Main(String[] args) dans 
G:\C#\cours_classe\cours_classe\Program.cs:ligne 21
Les Exceptions
• Constructeur des exceptions
public Exception ( string message )
• La propagation d’une exception se fait avec le mot clé throw.
• On veut vérifier que, lors de la modification de l’age d’une personne, celui‐
ci est bien compris entre 0 et 100, sinon on lève une exception.
public int age {
set {
if (value >= 0 && value <= 100)
_age = value;
else throw new Exception("age pas bon");
}
}
Les Exceptions
• Dans le Main(), on écrit : 
try {
CPersonne P1 = new CPersonne("casali", "alain", 30);
P1.age = 110;
P1.EcritConsole();
}
catch (Exception e){
Console.WriteLine(e);
}
• L’erreur suivante est affichée
System.Exception: age pas bon
à cours_classe.CPersonne.set_age(Int32 value) dans CPersonne.cs:ligne 45
à cours_classe.Program.Main(String[] args) dans Program.cs:ligne 20
• Si on veut uniquement le message d’erreur, il faut afficher e.Message
Conversion string → type primitif (2)
La plupart du temps, on doit transformer des données textuelles (saisies au 
clavier ou lues dans un fichier texte) vers des données numériques.
Pour s’assurer que la conversion se passe bien, il faut encapsuler l’appel à 
Parse() dans un bloc Try / Catch (sinon on peut faire planter le 
programme).
try {
int i = Int32.Parse("123.0");
Console.WriteLine(i);
}
catch (Exception e) {
Console.WriteLine(e.Message);
}
//Le format de la chaîne d'entrée est incorrect.
Conversion string → type primitif (2)
Au lieu d’encapsuler chaque appel à Parse(), on va 
utiliser la fonction statique TryParse() de profil : 
public static bool TryParse ( string
s, out type result );
Où type est un type de base (sauf string)
• Dans le Main(), on écrit : 
int i;
Int32.TryParse("123.0", out i);
Console.WriteLine(i); //0
Int32.TryParse("123", out i);
Console.WriteLine(i); //123
Construire ses exceptions
• On crée sa propre classe d’exception qui dérive de la classe 
Exception
class MException : Exception {
public MException(string msg) : base("On
lève une MException : " + msg) { }
}
• On l’utilise comme n’importe quelle classe dans le programme
public int age {
set {
if (value >= 0 && value <= 100)
{_age = value; }
else {throw new MException("age pas bon");}
}
}
Construire ses exceptions
Dans le Main(), on écrit : 
try {
CPersonne P1 = new CPersonne("casali", "alain", 30);
P1.age = 110;
P1.EcritConsole();
}
catch (MException e){
Console.WriteLine(e.Message);
}
• Le message suivant est affiché sur la console : 
On lève une MException : age pas bon
• cours_classe.MException: On lève une MException : age pas bon
à cours_classe.CPersonne.set_age(Int32 value) dans 
H:\C#\cours_classe\cours_classe\CPersonne.cs:ligne 45
à cours_classe.Program.Main(String[] args) dans 
H:\C#\cours_classe\cours_classe\Program.cs:ligne 63
Les vecteurs
• La classe ArrayList permet d'implémenter des 
tableaux de taille variable (des vecteurs) au cours de 
l'exécution du programme (C# 1.1).
• On la trouve dans l’espace de nom 
System.Collections.
• Le constructeur de la classe ne prend aucun argument
ArrayList ListeDePersonne = new
ArrayList();
• La propriété count permet de connaître le nombre 
d’éléments présents dans le vecteur
Console.WriteLine(ListeDePersonne.
Count); //0
Les vecteurs
• Pour ajouter un élément, on utilise la fonction Add()
CPersonne P = new CPersonne("Casali",
"alain", 30);
CPersonneS P1 = new CPersonneS
("Casali", "bob", 30,'M');
ListeDePersonne.Add(P1);
ListeDePersonne.Add(P);
ListeDePersonne.Add(ListeDePersonne[0]);
Remarque : on constate qu’on peut avoir des objets de 
types différents dans un même vecteur :’(
Les vecteurs
• Pour insérer un objet à une position donnée dans 
un vecteur, on utilise la fonction Insert() de profil :
public virtual void Insert ( int
index, Object value )

ListeDePersonne.Insert(1, P);
Remarque : la valeur de index doit être inférieure au 
nombre total d’éléments.
• Pour supprimer tous les éléments du vecteur, on 
utilise la fonction clear().
ListeDePersonne.Clear();
Les vecteurs
• Pour la recherche à partir du début, on utilise les fonctions publiques 
virtuelles :
int IndexOf (object o)
int IndexOf (object o, int posdeb)
int IndexOf (object o, int posdeb,
int combien)
Recherche de la première occurrence de l’élément o dans le 
vecteur entre les positions posdeb et posfin. Renvoie ‐1 
si l’élément est absent.
int i = ListeDePersonne.IndexOf(P1,1); //3
i = ListeDePersonne.IndexOf(P); // fait planter le
programme : pas de surcharge de Equals pour la
classe Cpersonne.
Les vecteurs
• On supprime un objet du vecteur avec la fonction 
Remove() de profil :
public virtual void Remove ( Object
obj )
ListeDePersonne.Remove(P1); // OK
ListeDePersonne.Remove(P); //plante
• On supprime l’objet à la i° position avec la fonction
RemoveAt() de profil :
public virtual void RemoveAt ( int
index )
ListeDePersonne.RemoveAt(0);
Les vecteurs
• Pour copier un vecteur dans un tableau (pas dans un 
vecteur), il faut utiliser une des fonctions CopyTo() de 
profil :
public virtual void CopyTo ( Array
array )
public virtual void CopyTo ( Array
array, int arrayIndex )

CPersonne[] TabPers = new


CPersonne[ListeDePersonne.Count];
ListeDePersonne.CopyTo(TabPers);
Attention le tableau garde les references du vecteur !!
Les vecteurs
Le principal défaut des vecteurs est qu’on ne peut pas 
accéder à un champ d’une de ses composantes. Si on écrit
ListeDePersonne[0].prenom = "bob";
Alors on obtient l’erreur suivante : 'object' ne
contient pas de définition pour
'prenom’.
• Pour pourvoir modifier le contenu d’une case, on est 
obligé de passer par un objet temporaire (plus 
introspection si nécessaire) :
CPersonne P2 = (CPersonne) ListeDePersonne[0];
P2.prenom = "bob";
ListeDePersonne[0] = P2;
Les vecteurs
• Depuis le framework 2.0, on utilise la classe List
générique pour créer des vecteurs. On construit un 
tel vecteur comme suit :
List<Type> Nom = new List<Type>();
• Dans notre cas, nous avons :
List<CPersonne> VPersonne = new
List<CPersonne>();
• Nous pouvons maintenant accéder aux champs des 
composantes du vecteur sans transtypage :
VPersonne[0].prenom = "bob";
• Tout ce dont nous avons fait mention avant (fonctions 
membres, propriétés) reste vrai pour les listes.
Accès aux fichiers
• Les accès aux fichiers sont gérés par la classe 
FileStream qui appartient à l’espace de nom 
System.IO.
• On peut ouvrir des fichiers en spécifiant le mode 
d’ouverture ainsi que le mode d’accès.
• Les 2 constructeurs usuels sont :
1. public FileStream ( string path,
FileMode mode )
2. public FileStream ( string path,
FileMode mode, FileAccess access )
Accès aux fichiers
• FileMode mode peut avoir les valeurs suivantes :
– Append : Ouvre le fichier s'il existe et accède à la fin du fichier, ou crée 
un nouveau fichier.
– Create: Spécifie que le système d'exploitation doit créer un fichier. Si 
le fichier existe, il est remplacé.
– CreateNew : Spécifie que le système d'exploitation doit créer un 
fichier.
– Open : Spécifie que le système d'exploitation doit ouvrir un fichier 
existant. 
– OpenOrCreate : Spécifie que le système d'exploitation doit ouvrir un 
fichier s'il existe ; sinon, un nouveau fichier doit être créé. 
– Truncate : Spécifie que le système d'exploitation doit ouvrir un fichier 
existant. Une fois ouvert, le fichier doit être tronqué de manière à ce 
que sa taille soit égale à zéro octet.
Accès aux fichiers
• FileAccess access peut avoir les valeurs suivantes :
– Read : Accès en lecture au fichier. Les données peuvent être lues à 
partir de ce fichier. 
– Write : Accès en écriture au fichier. Les données peuvent être écrites 
dans le fichier.
– ReadWrite : Accès en lecture et en écriture au fichier. Les données 
peuvent être écrites dans le fichier et lues à partir de celui‐ci.
• La fermeture d’un fichier se fait grâce à la fonction virtuelle 
Close() de profil :
public virtual void Close ()
• Dans le Main(), on écrit :
FileStream fs = new FileStream("tmp.txt",
FileMode.CreateNew, FileAccess.ReadWrite);

fs.Close();
Accès aux fichiers
• On peut verrouiller (une partie d’) un fichier de façon à ce que 
d’autres processus n’y accède pas en écriture (l’accès en lecture est 
autorisé) grâce à la fonction Lock(). Pour déverrouiller le fichier, 
on fait appel à Unlock().
public virtual void Lock ( long position, long
length )
public virtual void Unlock ( long position,
long length )
Dans ces deux cas, on pose (enlève) un verrou sur un fichier à partir de 
la position position, et sur length octets.
• On pourrait utiliser la classe FileStream pour lire et écrire dans un 
fichier, cependant, nous allons utiliser les classes :
– StreamReader et StreamWriter pour les fichiers textes,
– BinaryReader et BinaryWriter pour les fichiers binaires. 
Lecture d’un fichier texte
• La classe StreamReader permet de lire dans un fichier texte.
• Les constructeurs usuels sont :
– public StreamReader ( Stream stream )
Initialise une nouvelle instance de la classe StreamReader pour le flux 
spécifié. 
– public StreamReader ( string path )
Initialise une nouvelle instance de la classe StreamReader pour le 
nom de fichier spécifié. 
– public StreamReader ( Stream stream, Encoding
encoding )
Initialise une nouvelle instance de la classe StreamReader pour le flux 
spécifié, avec le codage de caractères spécifié. 
– public StreamReader ( string path, Encoding
encoding )
Initialise une nouvelle instance de la classe StreamReader pour le 
nom de fichier spécifié, avec le codage de caractères spécifié. 
Lecture d’un fichier texte
Les méthodes de la classe  sont :
• public override void Close ()
Ferme l'objet StreamReader et le flux sous‐jacent et libère 
les ressources système associées au lecteur. 
• public override int Peek ()
Retourne le prochain caractère disponible, mais ne le 
consomme pas. Renvoie ‐1 si aucun caractère n’est 
disponible.
• public override string ReadLine ()
Lit une ligne de caractères à partir du flux en cours et 
retourne les données sous forme de chaîne. 
• public override string ReadToEnd ()
Lit le flux entre la position actuelle et la fin du flux. 
Lecture d’un fichier texte
FileStream fs = new FileStream("tmp.txt",
FileMode.Open, FileAccess.Read);
StreamReader SR = new StreamReader(fs);
string ChaineLue = SR.ReadLine();
while (ChaineLue != null)
{
Console.WriteLine(ChaineLue);
ChaineLue = SR.ReadLine();
}
SR.Close();
fs.Close();
• Il faut penser à encapsuler les 2 premières lignes dans un bloc try / 
catch au cas où le fichier n’existe pas !
Encodage des caractères
• En C++ l’encodage des caractères est réalisé selon la norme 
ASCII, en C#, c’est la norme UNICODE qui est utilisée. Cela 
peut poser des soucis (notamment au niveau des lettres 
accentuées) si l’encodage n’est pas le bon.
• Le  système d’encodage est géré par la classe Encoding
qui appartient à l’espace de nom System.Text

• StreamReader SR = new StreamReader(fs,


ASCIIEncoding.Default);
• StreamReader SR = new StreamReader(fs,
UnicodeEncoding.Default); (UTF8)
Ecriture dans un fichier texte
• On va utiliser la classe StreamWriter pour écrire dans un 
fichier texte. Cette classe est la classe symétrique de 
StreamReader. 
• Les constructeurs usuels sont :
– public StreamWriter ( Stream stream )
Initialise une nouvelle instance de la classe StreamWriter pour le 
flux spécifié, à l'aide du codage UTF‐8 et de la taille de la 
mémoire tampon par défaut. 
– public StreamWriter ( string path )
Initialise une nouvelle instance de la classe StreamWriter pour le 
fichier spécifié sur le chemin d'accès spécifié, à l'aide du codage 
et de la taille de mémoire tampon par défaut. 
– Il existe aussi 2 constructeurs qui offrent la possibilité de 
spécifier l’encodage
Ecriture dans un fichier texte
Les méthodes de la classe  sont :
• public override void Close ()
Ferme l'objet StreamWriter actuel et le flux sous‐
jacent. 
• public override void Write ( Object
value )
Écrit un objet dans le flux (si la méthode ToString() a 
été implémentée).
• public override void WriteLine (
Object value )
Écrit un objet dans le flux (si la méthode ToString() a 
été implémentée).
Ecriture dans un fichier texte
static void Main(string[] args)
{
StreamWriter OUT = new StreamWriter("tmp.txt");
CPersonne P = new CPersonne("Casali", "alain", 30);
OUT.WriteLine(P);
OUT.Close();
}
Ecriture dans un fichier binaire
• On utilise la classe BinaryWriter pour écrire dans un 
fichier binaire.
• Il n’y a pas de constructeur avec comme argument un nom de 
fichier.
public BinaryWriter ( Stream output )
Initialise une nouvelle instance de la classe BinaryWriter en 
fonction du flux spécifié et utilisant UTF‐8 comme codage 
pour les chaînes. 
• Il existe aussi 1 constructeur qui offre la possibilité de 
spécifier l’encodage
Ecriture dans un fichier binaire
Les méthodes de la classe  sont :
• public override void Close ()
Ferme le BinaryWriter en cours et le flux sous‐jacent. 
• public virtual void Write ( TypePrimitif value )
Écrit une valeur de TypePrimitif dans le flux actuel.
• Pour écrire un objet de type CPersonne dans un fichier binaire il faut écrire  
(sans tenir compte de l’encodage) :
FileStream fs = new FileStream("tmp.dat",
FileMode.OpenOrCreate, FileAccess.Write);
BinaryWriter BW = new BinaryWriter(fs);
CPersonne P = new CPersonne("Casali", "alain",
30);
BW.Write((string) P._nom);
BW.Write((string) P.prenom);
BW.Write((int) P._age);
BW.Close();
Ecriture dans un fichier binaire
• Si on souhaite prendre en compte l’encodage
Encoding enc = UTF8Encoding.Default;
FileStream fs = new FileStream("tmp.dat",
FileAccess.Write);
BinaryWriter BW = new BinaryWriter(fs);
CPersonne P = new CPersonne("Casali", "alain",
30);
BW.Write((byte[]) enc.GetBytes(P._nom)));
BW.Write((byte[]) enc.GetBytes(P.prenom)));
BW.Write((int) P._age);
BW.Close();
• Attention:  cela ne suffit pas car on sait pas sur combien d’octets vont être 
codés les chaines de caractères encodées.
Ecriture dans un fichier binaire
• On va d’abord écrire dans le fichier binaire le nombre d’octets 
sur lesquels est encodée la chaine de caractère, puis la chaine 
elle‐même.

BW.Write((int) enc.GetByteCount(P._nom));
BW.Write(((byte[]) enc.GetBytes(P._nom)));
BW.Write((int) enc.GetByteCount(P.prenom));
BW.Write(((byte[]) enc.GetBytes(P.prenom)));
BW.Write((int) P._age);

Lecture dans un fichier binaire
• On va utiliser la classe BinaryReader pour lire dans un fichier 
binaire. Cette classe est la classe symétrique de BinaryWriter. 
• Le constructeur par défaut a pour profil :
public BinaryReader ( Stream input )
Initialise une nouvelle instance de la classe BinaryReader en 
fonction du flux fourni et à l'aide de UTF8Encoding. 
• Il existe aussi 1 constructeur qui offre la possibilité de 
spécifier l’encodage
Lecture dans un fichier binaire
Les méthodes de la classe  sont :
• public override void Close ()
Ferme le BinaryReader en cours et le flux sous‐jacent. 
• public virtual int ReadInt32 ()
Lit un entier signé de 4 octets à partir du flux actuel et avance la 
position actuelle du flux de 4 octets. 
• public virtual string ReadString ()
Lit une chaîne à partir du flux actuel. La chaîne est préfixée à l'aide 
de la longueur, codée comme un entier à raison de sept bits à la 
fois. 
• public virtual byte[] ReadBytes ( int count )
Lit count octets à partir du flux actuel dans un tableau d'octets et 
avance la position actuelle de count octets. 
• Il existe d’autres méthodes ReadType() permettant de lire des 
variable de type Type.
Lecture dans un fichier binaire
• En général, on ne connait pas le nombre de lecture qu’on doit effectuer, on 
connait seulement la nature des lectures. On doit donc écrire : 
FileStream fs = new FileStream("tmp.dat", FileMode.Open,
FileAccess.Read);
BinaryReader BR = new BinaryReader(fs);
try {
while (true) {
//faire les lectures
}
}
catch (EndOfStreamException) { }
finally
{
BR.Close();
fs.Close();
}
Lecture dans un fichier binaire
• La lecture associé à l’écriture sans prise en compte 
de l’encodage est la suivante :
string nom = BR.ReadString();
string prenom = BR.ReadString();
int age = BR.ReadInt32();
CPersonne P = new CPersonne(nom, prenom, age);
Console.WriteLine(P);
Lecture dans un fichier binaire
• La lecture associé à l’écriture avec prise en compte de l’encodage est la 
suivante :
int TailleChaine = (int)BR.ReadInt32();
byte[] buf = BR.ReadBytes(TailleChaine);
string nom = enc.GetString(buf);

TailleChaine = (int)BR.ReadInt32();
buf = BR.ReadBytes(TailleChaine);
string prenom = enc.GetString(buf);

int age = BR.ReadInt32();

CPersonne P2 = new CPersonne(nom, prenom, age);


Console.WriteLine(P2);
Sérialisation / désérialiation
• Consiste à enregistrer un objet dans un fichier sans 
avoir à se soucier de comment organiser les données.
• Pour sérialiser un objet il faut :
1. Inclure les espaces de nom 
System.Runtime.Serialization
System.Runtime.Serialization.Formatters.Binary
2. Marquer la classe de l’objet avec l’attribut 
[Serializable]
3. Créer un objet BinaryFormatter ainsi qu’un objet 
FileStream pour créer un fichier
4. Exécuter la méthode Serialize().
Sérialisation / désérialiation
• La désérialiation consiste à reconstituer l’objet 
sérialisé auparavant. 
• Pour désérialiser un objet il faut :
1. Inclure les espaces de nom 
System.Runtime.Serialization
System.Runtime.Serialization.Format
ters.Binary
2. Créer un objet BinaryFormatter ainsi qu’un 
objet FileStream pour lire dans le fichier
3. Exécuter la méthode Deserialize() appliquée 
sur l’objet BinaryFormatter.
Sérialisation / désérialiation

FileStream fs = new FileStream("tmp.dat",


FileMode.OpenOrCreate, FileAccess.Write);
CPersonne P = new CPersonne("Csali", "alain", 30);

BinaryFormatter bfEcr = new BinaryFormatter();


bfEcr.Serialize(fs, P);
fs.Close();

FileStream fs2 = new FileStream("tmp.dat", FileMode.Open,


FileAccess.Read);
BinaryFormatter bfLec = new BinaryFormatter();
CPersonne P2 = (CPersonne) bfLec.Deserialize(fs2);
fs2.Close();
Console.WriteLine(P2);// Casali, alain, 30

Vous aimerez peut-être aussi