Cours complet langage C#

Cours complet langage C# de A à Z
Extrait du cours:
C# est un langage récent. Il a été disponible en versions beta depuis l’année 2000 avant d’être officiellement disponible en février 2002 en même temps que la plate-forme .NET de Microsoft à laquelle il est lié. C# ne peut fonctionner qu’avec cet environnement d’exécution, environnement disponible pour le moment que sur les machines Windows NT, 2000 et XP. Cours complet langage C# en pdf
Avec la plate-forme .NET, trois nouveaux langages sont apparus : C#, VB.VET, JSCRIPT.NET. C# est largement une « copie » de Java. VB.NET et JSCRIPT.NET sont des extensions de Visual basic et Jscript pour la plate-forme .NET. Celle-ci rend disponible aux programmes qui s’exécutent en son sein un ensemble très important de classes, classes très proches de celles que l’on trouve au sein des machines virtuelles Java. En première approximation, on peut dire que la plate-forme .NET est un environnement d’exécution analogue à une machine virtuelle Java. On peut noter cependant deux différences importantes :
- la plate-forme .NET ne s'exécute que sur les machines Windows alors que Java s'exécute sur différents OS (windows, unix, macintosh).
- la plate-forme .NET permet l'exécution de programmes écrits en différents langages. Il suffit que le compilateur de ceux-ci sache produire du code IL (Intermediate Language), code exécuté par la machine virtuelle .NET. Toutes les classes de .NET sont disponibles aux langages compatibles .NET ce qui tend à gommer les différences entre langages dans la mesure où les programmes utilisent largement ces classes. Le choix d'un langage .NET devient affaire de goût plus que de performances.
1.2.4.3 Déclaration des variables
Une variable est identifiée par un nom et se rapporte à un type de données. C# fait la différence entre majuscules et minuscules.
Ainsi les variables FIN et fin sont différentes.
Les variables peuvent être initialisées lors de leur déclaration. La syntaxe de déclaration d'une ou plusieurs variables est :
identificateur_de_type variable1,variable2,...,variablen;
où identificateur_de_type est un type prédéfini ou bien un type défini par le programmeur.
1.2.5 Les conversions entre nombres et chaînes de caractères nombre -> chaîne "" + nombre
chaine -> int int.Parse(chaine) ou Int32.Parse
chaîne -> long long.Parse(chaine) pu Int64.Parse
chaîne -> double double.Parse(chaîne) ou Double.Parse(chaîne)
chaîne -> float float.Parse(chaîne) ou Float.Parse(chaîne)
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 appelée exception en C#. Cette erreur peut être gérée par la clause try/catch suivante :
try{
appel de la fonction susceptible de générer l'exception
} catch (Exception e){
traiter l'exception e
}
instruction suivante
Si la fonction ne génère pas d'exception, on passe alors à instruction suivante, sinon on passe dans le corps de la clause catch puis à instruction suivante. Nous reviendrons ultérieurement sur la gestion des exceptions. Voici un programme présentant les principales techniques de conversion entre nombres et chaînes de caractères. Dans cet exemple la fonction affiche écrit à l'écran la valeur de son paramètre. Ainsi affiche(S) écrit la valeur de S à l'écran.
// espaces de noms importés
using System;
// la classe de test
public class conv1{
public static void Main(){
String S;
const int i=10; const long l=100000;
const float f=45.78F;
double d=-14.98;
// nombre --> chaîne
S=""+i;
affiche(S);
S=""+l;
affiche(S);
S=""+f;
affiche(S);
S=""+d;
affiche(S);
//boolean --> chaîne
const bool b=false;
S=""+b;
affiche(S);
// chaîne --> int
int i1;
i1=int.Parse("10");
affiche(""+i1);
try{
i1=int.Parse("10.67");
affiche(""+i1);
} catch (Exception e){
affiche("Erreur "+e.Message);
}
// chaîne --> long
long l1;
l1=long.Parse("100");
affiche(""+l1);
try{
l1=long.Parse("10.675");
affiche(""+l1);
} catch (Exception e){
affiche("Erreur "+e.Message);
}
// chaîne --> double
double d1;
d1=double.Parse("100,87");
affiche(""+d1);
try{
d1=double.Parse("abcd");
affiche(""+d1);
} catch (Exception e){
affiche("Erreur "+e.Message);
}
// chaîne --> float
float f1;
f1=float.Parse("100,87");
affiche(""+f1);
try{
d1=float.Parse("abcd");
affiche(""+f1);
} catch (Exception e){
affiche("Erreur "+e.Message);
}
}// fin main
public static void affiche(String S){
Console.Out.WriteLine("S="+S);
}
}// fin classe
Les résultats obtenus sont les suivants :
S=10
S=100000
S=45.78
S=-14.98
S=False
S=10
S=Erreur The input string was not in a correct format.
S=100
S=Erreur The input string was not in a correct format.
S=100.87
S=Erreur The input string was not in a correct format.
S=100.87
S=Erreur The 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");
1.2.6 Les tableaux de données
Un tableau 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};
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}};
Le nombre d'éléments dans chacune des dimensions peut être obtenue par la méthode GetLenth(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. L'exemple ci-dessous illustre la création d'un tableau de tableaux :
// 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
Ici noms[i] est un tableau de i+1 éléments. Comme noms[i] est un tableau, noms[i].Length est son nombre d'éléments. Voici un exemple regroupant les trois types de tableaux que nous venons de présenter :
// tableaux
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.Out.WriteLine("entiers["+i+"]="+entiers[i]);
}//for
// un tableau à 2 dimensions initialisé
double[,] réels=new double[,] { {0.5, 1.7}, {8.4, -6}};
for (int i=0;i<réels.GetLength(0);i++){
for (int j=0;j<réels.GetLength(1);j++){ Console.Out.WriteLine("réels["+i+","+j+"]="+réels[i,j]);
}//for j
}//for i
// 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
// 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
A l'exécution, nous obtenons les résultats suivants :
entiers[0]=0
entiers[1]=10
entiers[2]=20
entiers[3]=30
réels[0,0]=0.5
réels[0,1]=1.7
réels[1,0]=8.4
réels[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
1.3 Les instructions élémentaires de C#
On distingue
1 les instructions élémentaires exécutées par l'ordinateur.
2 les instructions de contrôle du déroulement du programme.
Les instructions élémentaires apparaissent clairement lorsqu'on considère la structure d'un micro-ordinateur et de ses périphériques.
- lecture d'informations provenant du clavier
- traitement d'informations
- écriture d'informations à l'écran
- lecture d'informations provenant d'un fichier disque
- écriture d'informations dans un fichier disque
1.3.1 Ecriture sur écran
Il existe différentes instructions d'écriture à l'écran :
Console.Out.WriteLine(expression)
Console.WriteLine(expression)
Console.Error.WriteLine (expression)
où expression est tout type de donnée qui puisse être converti en chaîne de caractères pour être affiché à l'écran. Dans les exemples
vus jusqu'ici, nous n'avons utilisé que l'instruction Console.Out.WriteLine(expression).
La classe System.Console donne accès aux opérations d'écriture écran (Write, WriteLine). La classe Console a deux propriétés Out et
Error qui sont des flux d'écriture de type StreamWriter :
- Console.WriteLine() est équivalent à Console.Out.WriteLine() et écrit sur le flux Out associé habituellement à l'écran.
- Console.Error.WriteLine() écrit sur le flux Error, habituellement associé lui aussi l'écran.
Les flux Out et Error sont associés par défaut l'écran. Mais ils peuvent être redirigés vers des fichiers texte au moment de l'exécution du programme comme nous le verrons prochainement.
1.3.2 Lecture de données tapées au clavier
Le flux de données provenant du clavier est désigné par l'objet Console.In de type StreamReader. Ce type d'objets permet de lire une ligne de texte avec la méthode ReadLine :
String ligne=Console.In.readLine();
La ligne tapée au clavier est rangée dans la variable ligne et peut ensuite être exploitée par le programme.Le flux In peut être redirigé vers un fichier comme les flux Out et Error.
1.3.3 Exemple d'entrées-sorties
Voici un court programme d'illustration des opérations d'entrées-sorties clavier/écran :
using System;
public class io1{
public static void Main (){
// écriture sur le flux Out object obj=new object();
Console.Out.WriteLine(""+obj);
// écriture sur le flux Error int i=10;
Console.Error.WriteLine("i="+i);
// lecture d'une ligne saisie au clavier
Console.Out.Write("Tapez une ligne : ");
string ligne=Console.In.ReadLine();
Console.Out.WriteLine("ligne="+ligne);
}//fin main
}//fin classe
et les résultats de l'exécution :
System.Object
i=10
Tapez une ligne : je suis là
ligne=je suis là
Les instructions
object obj=new object();
Console.Out.WriteLine(""+obj);
ont pour but de montrer que n'importe quel objet peut faire l'objet d'un affichage. Nous ne chercherons pas ici à expliquer la signification de ce qui est affiché.
1.3.4 Redirection des E/S
Il existe sous DOS et UNIX trois périphériques stadard appelés :
- périphérique d'entrée standard - désigne par défaut le clavier et porte le n° 0
- périphérique de sortie standard - désigne par défaut l'écran et porte le n° 1
- périphérique d'erreur standard - désigne par défaut l'écran et porte le n° 2
En C#, le flux d'écriture Console.Out écrit sur le périphérique 1, le flux d'écriture Console.Error écrit sur le périphérique 2 et le flux de lecture Console.In lit les données provenant du périphérique 0.
Lorsqu'on lance un programme sous Dos ou Unix, on peut fixer quels seront les périphériques 0, 1 et 2 pour le programme exécuté. Considérons la ligne de commande suivante :
Derrière les arguments argi du programme pg, on peut rediriger les périphériques d'E/S standard vers des fichiers:
1>out.txt redirige la sortie n° 1 vers le fichier out.txt. Cela entraîne que dans le programme le flux Console.Out écrira ses données dans le fichier out.txt
1>>out.txt idem, mais les données écrites sont ajoutées au contenu actuel du fichier out.txt.
2>error.txt redirige la sortie n° 2 vers le fichier error.txt. Cela entraîne que dans le programme le flux Console.Error écrira ses données dans le fichier error.txt
2>>error.txt idem, mais les données écrites sont ajoutées au contenu actuel du fichier error.txt.
1>out.txt 2>error.txt Les périphériques 1 et 2 sont tous les deux redirigés vers des fichiers
On notera que pour rediriger les flux d'E/S du programme pg vers des fichiers, le programme pg n'a pas besoin d'être modifié.
C'est l'OS qui fixe la nature des périphériques 0,1 et 2. Considérons le programme suivant :
// imports
using System;
// redirections
public class console2{ public static void Main(String[] args){
// lecture flux In
string data=Console.In.ReadLine();
// écriture flux Out
Console.Out.WriteLine("écriture dans flux Out : " + data);
// écriture flux Error
Console.Error.WriteLine("écriture dans flux Error : " + data);
}//Main
}//classe
Faisons une première exécution de ce programme :
E:\data\serge\MSNET\c#\bases\1>console2

test
écriture dans flux Out : test
écriture dans flux Error : test
L'exécution précédente ne redirige aucun des flux d'E/S standard In, Out, Error. Nos allons maintenant rediriger les trois flux. Le flux In sera redirigé vers un fichier in.txt, le flux Out vers le fichier out.txt, le flux Error vers le fichier error.txt. Cette redirection a lieu sur la ligne de commande sous la forme
E:\data\serge\MSNET\c#\bases\1>console2 0out.txt 2>error.txt
L'exécution donne les résultats suivants :
E:\data\serge\MSNET\c#\bases\1>more in.txt test
E:\data\serge\MSNET\c#\bases\1>console2 0out.txt 2>error.txt
E:\data\serge\MSNET\c#\bases\1>more out.txt écriture dans flux Out : test
E:\data\serge\MSNET\c#\bases\1>more error.txt écriture dans flux Error : test
On voit clairement que les flux Out et In n'écrivent pas sur les mêmes périphériques.
1.3.5 Affectation de la valeur d'une expression à une variable
On s'intéresse ici à l'opération variable=expression;
L'expression peut être de type : arithmétique, relationnelle, booléenne, caractères
1.3.5.1 Interprétation de l'opération d'affectation
est elle-même une expression dont l'évaluation se déroule de la façon suivante :
- La partie droite de l'affectation est évaluée : le résultat est une valeur V.
- la valeur V est affectée à la variable
- la valeur V est aussi la valeur de l'affectation vue cette fois en tant qu'expression.
C'est ainsi que l'opération
V1=V2=expression
est légale. A cause de la priorité, c'est l'opérateur = le plus à droite qui va être évalué. On a donc
V1=(V2=expression)
L'expression V2=expression est évaluée et a pour valeur V. L'évaluation de cette expression a provoqué l'affectation de V à V2.
L'opérateur = suivant est alors évalué sous la forme :
V1=V
La valeur de cette expression est encore V. Son évaluation provoque l'affectation de V à V1.
Ainsi donc, l'opération V1=V2=expression est une expression dont l'évaluation
1 provoque l'affectation de la valeur de expression aux variables V1 et V2
2 rend comme résultat la valeur de expression.
On peut généraliser à une expression du type :
V1=V2=....=Vn=expression
1.3.5.2 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.
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
etc...
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);
La définition complète de la classe Math est la suivante :
// from module 'c:\winnt\microsoft.net\framework\v1.0.2914\mscorlib.dll'
public sealed class Math : object
{
// Fields
public static const double E; public static const double PI;
// Constructors
// Methods
public static long Abs(long value); public static int Abs(int value); public static short Abs(short value);
public static SByte Abs(SByte value); public static double Abs(double value); public static Decimal Abs(Decimal value);
public static float Abs(float value); public static double Acos(double d); public static double Asin(double d);
public static double Atan(double d); public static double Atan2(double y, double x); public static double Ceiling(double a);
public static double Cos(double d); public static double Cosh(double value); public virtual bool Equals(object obj);
public static double Exp(double d); public static double Floor(double d); public virtual int GetHashCode();
public Type GetType();
public static double IEEERemainder(double x, double y); public static double Log(double a, double newBase); public static double Log(double d);
public static double Log10(double d); public static Decimal Max(Decimal val1, Decimal val2); public static byte Max(byte val1, byte val2);
public static short Max(short val1, short val2); public static UInt32 Max(UInt32 val1, UInt32 val2); public static UInt64 Max(UInt64 val1, UInt64 val2); public static long Max(long val1, long val2); public static int Max(int val1, int val2); public static double Max(double val1, double val2);
public static float Max(float val1, float val2); public static UInt16 Max(UInt16 val1, UInt16 val2); public static SByte Max(SByte val1, SByte val2);
public static int Min(int val1, int val2); public static UInt32 Min(UInt32 val1, UInt32 val2);
public static short Min(short val1, short val2); public static UInt16 Min(UInt16 val1, UInt16 val2); public static long Min(long val1, long val2);
public static double Min(double val1, double val2); public static Decimal Min(Decimal val1, Decimal val2); public static UInt64 Min(UInt64 val1, UInt64 val2);
public static float Min(float val1, float val2); public static byte Min(byte val1, byte val2); public static SByte Min(SByte val1, SByte val2);
public static double Pow(double x, double y); public static double Round(double a); public static Decimal Round(Decimal d);
public static Decimal Round(Decimal d, int decimals); public static double Round(double value, int digits); public static int Sign(SByte value);
public static int Sign(short value); public static int Sign(int value); public static int Sign(long value); public static int Sign(Decimal value); public static int Sign(double value); public static int Sign(float value); public static double Sin(double a);
public static double Sinh(double value); public static double Sqrt(double d);
public static double Tan(double a); public static double Tanh(double value); public virtual string ToString();
} // end of System.Math
1.3.5.3 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], [ ( )],[ *, /, %], [+, -]
Les opérateurs d'un même bloc [ ] ont même priorité.
1.3.5.4 Expressions relationnelles
Les opérateurs sont les suivants :
<, <=, ==, !=, >, >=
priorités des opérateurs
- >, >=, <, <=
- ==, !=
Le résultat d'une expression relationnelle est le booléen false si expression fausse true sinon.
boolean fin;
int x;
fin=x>4;
Comparaison de deux caractères
Soient deux caractères C1 et C2. Il est possible de les comparer avec les opérateurs
<, <=, ==, !=, >, >=
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'
Comparaison de deux chaînes de caractères
Elles sont comparées caractère par caractère. La première inégalité rencontrée entre deux caractères induit une inégalité de même
sens sur les chaînes.
Exemples :
Soit à comparer les chaînes "Chat" et "Chien"
"Chat" "Chien"
-----------------------
'C' = 'C'
'h' = 'h'
'a' < 'i'
Cette dernière inégalité permet de dire que "Chat" < "Chien".
Soit à comparer les chaînes "Chat" et "Chaton". Il y a égalité tout le temps jusqu'à épuisement de la chaîne "Chat". Dans ce cas, la
chaîne épuisée est déclarée la plus "petite". On a donc la relation
"Chat" < "Chaton".
Fonctions de comparaisons de deux chaînes
On peut utiliser ici les opérateurs relationnels <, <=, ==, !=, >, >= ou des méthodes de la classe String :
String chaine1, chaine2;
chaine1=…;
chaine2=…;
int i=chaine1.CompareTo(chaine2); int i=chaine1.CompareTo(chaine2);
boolean egal=chaine1.Equals(chaine2) boolean egal=chaine1.Equals(chaine2)
Ci-dessus, la variable i aura la valeur :
0 si les deux chaînes sont égales
1 si chaîne n°1 > chaîne n°2