← Développement

Programmation C#

Sommaire

1. Le langage C# et la plateforme .NET

C#

Plateforme Microsoft .NET

Ensemble d'outils et de technologies destinées au développement d'applications ciblant des configurations logicielles et matérielles variées.

Rôle
.NET FrameworkEnsemble de bibliothèques de classes (API) donnant accès aux fonctionnalités du système
.NET CoreDéveloppement multi-plateforme (Windows, Mac, Linux), architectures en microservices (cloud), conteneurs
Type d'applicationWindowsLinuxMacOSAndroidiOS
Console
Fenêtrée (WinForms/WPF)
Web
Mobile

Du code source au programme exécutable

Programmation (code source) → Compilation → Exécution (code binaire)

2. Premier programme

using System;

namespace HelloWorld
{
    class Program
    {
        /// <summary>
        /// Programme HelloWorld
        /// </summary>
        static void Main(string[] args)
        {
            // affichage dans la console
            Console.WriteLine("Hello world !");
            Console.ReadLine();
        }
    }
}
ÉlémentRôle
using System;Le Framework .NET est composé de bibliothèques de classes organisées en espaces de noms (namespaces) ; cette ligne indique que le code utilise l'espace de noms System (ex. la classe Console)
namespace HelloWorldL'espace de noms correspond au programme
class ProgramNom de classe par défaut d'une application console
static void Main(string[] args)La méthode Main est le point d'entrée de l'application ; elle contient les instructions exécutées

3. Variables, types, constantes

Les variables

// Syntaxe : typeVar nomVar;
string nom;
double note;
int coeff;

Règles de nommage :

Les types de données primitifs

TypeDescriptionTaillePlage de valeurs
intNombres entiers32 bits-2 147 483 648 à 2 147 483 647
longNombres entiers longs64 bits-2⁶ à 2⁶-1
floatVirgule flottante32 bits±1,5×10⁻⁴⁵ à ±3,4×10³⁸
doubleVirgule flottante (double précision, plus précis)64 bits±5,0×10⁻³⁆⁴ à ±1,7×10³⁰⁸
decimalNombre décimal128 bits28 chiffres significatifs
stringChaîne de caractères16 bits/caractèredélimiteur "
charCaractère unique16 bitsdélimiteur '
boolBooléen8 bitstrue ou false

Mot-clé var (inférence de type) : le compilateur C# détermine le type d'une variable en fonction de la valeur assignée. Exemple : var nomClient = "Jean";

Les constantes

const int tauxTVA = 20;
const string devise = "Euro";
const char symbole = '€';

On utilise une constante lorsque la valeur d'une donnée n'est pas amenée à être modifiée. Le mot-clé const scelle la donnée. Par convention, les constantes sont déclarées en début de programme.

4. Affectation et conversions

Affectation (assignation) : opération qui attribue une valeur à une variable. En C#, l'opérateur d'affectation est =.

nom = "Martin";
note = 12.5;
resultat = total / 10;
int age = 10;   // déclaration + initialisation en une seule instruction

Conversions :

int note1;
note1 = int.Parse("12");         // chaîne → valeur numérique

string valeur;
valeur = note1.ToString();       // valeur numérique → chaîne

double res;
res = (double)note1;             // cast entre types numériques

5. Opérateurs mathématiques

OpérateurSignification
+Addition (variables numériques) / concaténation (variables string)
-Soustraction
*Multiplication
/Division — si les 2 opérandes sont double, résultat double ; si on divise un entier par un autre, résultat entier
%Modulo, reste de la division euclidienne
++Incrémentation (ajoute 1)
--Décrémentation (soustrait 1)

6. Les entrées / sorties (mode console)

Classe Console : composant du Framework .NET permettant d'interagir avec la fenêtre de commandes (affichage et saisie).

Affichage

Console.Write("Bonjour");                     // curseur reste en fin de ligne
Console.WriteLine("Au revoir");               // curseur passe en début de ligne suivante
string nom = "Hugo";
Console.Write("Bonjour {0} ", nom);           // chaîne composite
Console.Write("Bonjour " + nom);              // concaténation
Console.Write($"Bonjour {nom}");              // interpolation de chaîne

Caractères spéciaux : \n (saut de ligne), \t (tabulation), \" (guillemet).

Saisie

string nom = Console.ReadLine();              // récupère une chaîne saisie, terminée par Entrée
int nb = int.Parse(Console.ReadLine());       // ReadLine() renvoie toujours une string → conversion
Console.Read();                               // récupère un seul caractère saisi

7. Structures conditionnelles

Structures de contrôle permettant d'exécuter un traitement ou un autre selon l'évaluation d'une condition. Deux structures existent en C# : if...else et switch.

L'instruction if

if (age >= 18)
{
    Console.WriteLine("Vous êtes majeur");
}
else
{
    Console.WriteLine("Vous êtes mineur");
}
if (temperature < 0)
    Console.WriteLine("Eau à l'état solide");
else if (temperature < 100)
    Console.WriteLine("Eau à l'état liquide");
else
    Console.WriteLine("Eau à l'état gazeux");

La condition

Opérateurs de comparaison

OpérateurSignification
==égal à (ne pas confondre avec = l'affectation)
!=différent de
<inférieur
<=inférieur ou égal
>supérieur
>=supérieur ou égal

Opérateurs logiques

OpérateurSignification
&&ET — vraie si les 2 conditions sont vraies
||OU — vraie si l'une des 2 conditions est vraie
!NON — inverse (négation) de la condition

L'instruction switch

switch (operateur)   // variable de type int, char, string ou bool uniquement
{
    case '+':
        res = a + b;
        break;
    case '-':
        res = a - b;
        break;
    default:
        Console.WriteLine("opérateur inconnu");
        break;
}

8. Structures itératives (boucles)

Permettent de répéter un traitement en fonction de l'évaluation d'une condition.

StructureNombre d'itérations
forConnu dès le départ
whileIndéterminé, condition testée avant → 0 à n exécutions
do...whileIndéterminé, condition testée après → 1 à n exécutions (au moins une fois)

while

Console.Write("Saisir un nombre positif : ");
int nb = int.Parse(Console.ReadLine());
while (nb < 0)
{
    Console.Write("Saisir un nombre positif : ");
    nb = int.Parse(Console.ReadLine());
}
Console.Write("Merci !");

Pas de point-virgule après la condition. Si aucune instruction ne fait évoluer la condition → boucle infinie.

do...while

int nb;
do
{
    Console.Write("Saisir un nombre positif : ");
    nb = int.Parse(Console.ReadLine());
} while (nb < 0);

Point-virgule obligatoire après la condition. Le bloc d'instructions est exécuté au moins une fois (évaluation en sortie de boucle).

for

for (int i = 0; i <= 100; i++)
{
    Console.WriteLine(i);
}

Trois arguments séparés par ; :

  1. Initialisation de la variable-indice — exécutée une seule fois, à l'entrée dans la boucle
  2. Condition portant sur la variable-indice — évaluée avant chaque itération
  3. Pas — exécuté à la fin de chaque itération, avant réévaluation de la condition (incrémentation ou décrémentation)

9. Méthodes (procédures / fonctions)

Une méthode (fonction membre en POO) regroupe un ensemble d'instructions, peut recevoir des données en entrée (paramètres) et renvoyer un résultat.

Objectifs : code modulaire, plus lisible et maintenable, factorisation (évite la duplication), réutilisation, facilite tests/débogage et documentation.

Définir une méthode

static typeRetour NomMethode([paramètres])
{
    // instructions
    [return ...]
}

Appeler une méthode

[resultat = ] NomMethode([arguments]);

Les arguments (valeurs transmises à l'appel) doivent correspondre aux paramètres attendus : nombre, ordre, type, mode de passage.

// Sans paramètre, sans retour
static void DireBonjour()
{
    Console.WriteLine("Bonjour !");
}
// Appel : DireBonjour();

// Avec paramètres, sans retour
static void DireBonjour(string nom, string prenom)
{
    Console.WriteLine($"Bonjour {prenom} {nom} !");
}
// Appel : DireBonjour(leNom, lePrenom);

// Avec paramètres et retour
static double CalculTTC(int prixHT, double tauxTVA)
{
    double prixTTC = prixHT * (1 + tauxTVA / 100);
    return prixTTC;
}
// Appel : double leTTC = CalculTTC(unPrix, unTaux);

Passage des paramètres

ModeMot-clé C#Comportement
Entrée (par valeur)(aucun, par défaut)Une copie de la valeur est transmise. Modification dans la méthode = locale, non répercutée à l'appelant
Entrée-sortie (par référence)refLe paramètre a déjà une valeur à l'appel ; peut être modifié, la nouvelle valeur est répercutée à l'appelant
Sortie (par référence)outLe paramètre n'a pas de valeur au moment de l'appel ; la méthode doit lui en assigner une, répercutée à l'appelant
// ref : entrée-sortie
static void Incrementer(ref int nombre, int valeur)
{
    nombre = nombre + valeur;
}
// Appel : Incrementer(ref nb1, nb2);  ← "ref" obligatoire devant l'argument, qui doit être initialisé

// out : sortie
static bool Division(double nb1, double nb2, out double res)
{
    res = 0;
    bool ok = false;
    if (nb2 != 0)
    {
        res = nb1 / nb2;
        ok = true;
    }
    return ok;
}
// Appel : if (Division(a, b, out result) == true) { ... }

Portée des variables

Documenter une méthode

/// <summary>
/// Méthode qui calcule l'hypoténuse d'un triangle rectangle
/// </summary>
/// <param name="b">base du triangle</param>
/// <param name="h">hauteur du triangle</param>
/// <returns>hypoténuse du triangle</returns>
static double CalculerHypotenuse(int b, int h)
{ ... }

Tags : <summary> (rôle de la méthode), <param> (rôle de chaque paramètre), <returns> (valeur de retour). Cette documentation s'affiche automatiquement dans l'éditeur de code lors de l'appel de la méthode (comme pour les classes déjà documentées du Framework .NET, ex. Math.Round()).

10. Structures de données

Permettent de regrouper et d'organiser un ensemble (une collection) de données. Opérations courantes : parcours, insertion, suppression, recherche.

Tableaux (Array)

Stockent de manière consécutive un nombre fini d'éléments de même type. Indices en base 0 (1er élément à l'indice 0, dernier à l'indice n-1).

// Déclaration + instanciation (taille fixe, structure statique)
double[] tab1 = new double[5];

// Déclaration + initialisation directe (dimensionnement automatique)
int[] tab3 = {5, 10, 4, 3, 1, 25};

// Accès à un élément
Console.Write(tab3[0]);      // affiche 5
tab3[2] = 7;                 // remplace la valeur à l'indice 2
// tab3[7] provoquerait une erreur outOfRangeException (débordement)

// Parcours avec indices (for / while)
for (int i = 0; i <= 5; i++)
    Console.WriteLine(tab3[i]);

// Parcours en énumérant les éléments (foreach) — lecture seule
foreach (int elem in tab3)
    Console.WriteLine(elem);

Un tableau est un type référence : sans initialisation, sa valeur est null.

Tableaux à deux dimensions

int[,] tab2 = {{5,10,4},{3,1,25}};    // 2 lignes, 3 colonnes
Console.Write(tab2[1,2]);             // ligne 1, colonne 2 → 25
tab2[0,1] = 7;                        // remplace la valeur à ligne 0, colonne 1

for (int i = 0; i <= 1; i++)
    for (int j = 0; j <= 2; j++)
        Console.WriteLine(tab2[i,j]);

Classe Array (méthodes utiles) : propriété Length ; méthodes Copy(), Clear(), Exists(), Find(), GetLength(), GetUpperBound(), Sort()

Listes (List<T>)

Structure dynamique (taille non fixée), stocke de manière ordonnée un nombre indéfini d'éléments de même type, accessibles par index (base 0). Namespace System.Collections.Generic.

List<string> mesAmis = new List<string>();
mesAmis.Add("Elodie");
mesAmis.Add("Mario");
mesAmis.Add("Harry");

Console.WriteLine("J'ai {0} amis", mesAmis.Count);
Console.WriteLine(mesAmis[0]);          // accès par indexeur

foreach (string nom in mesAmis)
    Console.WriteLine(nom);

mesAmis.Remove("Mario");                // suppression par valeur
mesAmis.RemoveAt(0);                    // suppression par indice

for (int i = 0; i <= mesAmis.Count - 1; i++)
    Console.WriteLine(mesAmis[i]);

Dictionnaires (Dictionary<TKey, TValue>)

Structure dynamique qui stocke des couples clé/valeur ; la clé est unique. Namespace System.Collections.Generic.

Dictionary<string, int> leDico = new Dictionary<string, int>();
leDico.Add("Julia", 10);
leDico.Add("Leo", 12);
// leDico.Add("Julia", 4);   → déclenche une exception (clé déjà existante)

Console.WriteLine(leDico.Count);          // nombre d'entrées
Console.WriteLine(leDico["Leo"]);         // accès par clé → 12

leDico["Steeven"] = 15;                   // clé existante → valeur remplacée
leDico["Mario"] = 8;                      // clé absente → nouvelle entrée ajoutée

leDico.ContainsKey("Steeven");            // teste la présence d'une clé → true/false

foreach (int v in leDico.Values)          // parcours des valeurs
    Console.WriteLine(v);

foreach (string k in leDico.Keys)         // parcours des clés
    Console.WriteLine("{0}->{1}", k, leDico[k]);

foreach (KeyValuePair<string, int> entree in leDico)   // parcours des couples clé/valeur
    Console.WriteLine("{0}->{1}", entree.Key, entree.Value);

11. Pense-bête — quelle structure choisir ?

Nombre d'itérations connu        →  for
Nombre d'itérations indéterminé  →  while (0 à n fois) ou do..while (1 à n fois, au moins 1 exécution)

Collection de taille fixe, même type       →  tableau (Array)
Collection dynamique ordonnée, même type   →  List<T>
Collection dynamique de couples clé/valeur →  Dictionary<TKey, TValue>