🌐
🔍 100%
👁️

Chapitre 1 : Architecture .NET & Fondamentaux C#

Module : Programmation .net C#

Niveau : 4ème Génie Informatique (Spécialité Data Science)

Prérequis : TP1 (Fondamentaux) validé

Introduction

Dans le TP1, vous avez manipulé la syntaxe de base pour créer une application console simple. Ce chapitre a pour but de formaliser ces connaissances et de "lever le capot" : comprendre comment votre code C# est structuré, compilé et géré en mémoire.

I. De dotnet run au Processeur : Architecture .NET

1. Le flux de compilation (Compilation Pipeline)

Contrairement au C++ (compilé directement en code machine) ou au Python (interprété), C# utilise un modèle hybride :

  1. Source (.cs) → CIL (IL) : Le compilateur Roslyn transforme votre code en Common Intermediate Language. C'est un assembleur universel stocké dans votre .dll ou .exe.
  2. CLR (Common Language Runtime) : Au lancement, le runtime charge cet IL.
  3. JIT (Just-In-Time) : Le JIT compile l'IL en code machine natif (x64/ARM) à la volée, optimisé pour le processeur actuel.
Code Source (.cs) Compilateur (Roslyn) Code IL (.dll / .exe) CLR & JIT (Natif CPU)

Figure 1 : Le chemin de compilation C#

Note : Ce modèle garantit que le même binaire tourne sur Windows et Linux, tout en offrant des performances proches du C++ grâce aux optimisations du JIT.

2. Top-Level Statements

Les programmes modernes (C# 10+) ne nécessitent plus d'écrire explicitement public static void Main. Le code écrit directement dans Program.cs est automatiquement encapsulé dans le point d'entrée Main par le compilateur.

II. Les Types de Base du Système .NET

En C#, tout hérite ultimement de System.Object. Pour un développeur, la distinction critique n'est pas "texte vs nombre", mais Stack vs Heap (Lieu de stockage).

1. Tableau Récapitulatif des Types Usuels

Type C# Type .NET (CTS) Famille (Stockage) Usage en Data Science
int System.Int32 Valeur (Stack) Entiers standard (Index, Compteurs).
long System.Int64 Valeur (Stack) Grands entiers (Big Data, IDs BDD).
double System.Double Valeur (Stack) Calculs scientifiques (virgule flottante IEEE 754).
decimal System.Decimal Valeur (Stack) Finance (128 bits, haute précision, pas d'erreurs d'arrondi).
bool System.Boolean Valeur (Stack) Logique (true/false).
char System.Char Valeur (Stack) Un caractère Unicode (16 bits).
DateTime System.DateTime Valeur (Stack) Gestion du temps (Struct). Indispensable pour les séries temporelles.
string System.String Référence (Heap) Texte. Attention : Stocké comme un objet (Pointeur).

2. Comprendre la Mémoire : L'analogie du "Plan de Travail" vs "L'Entrepôt"

Pour simplifier, imaginez votre mémoire RAM divisée en deux zones distinctes :

🔵 La Stack (Pile)

C'est votre "Plan de travail personnel".

  • Vitesse : Extrêmement rapide (immédiat).
  • Durée de vie : Courte. Quand une fonction se termine, le plan de travail est vidé automatiquement.
  • Ce qu'on y met : Les petits outils simples (Types Valeur : int, double, bool).
  • Exemple : Un post-it avec le nombre "42" écrit dessus.

📦 La Heap (Tas)

C'est un "Grand Entrepôt" distant.

  • Vitesse : Plus lent (il faut aller chercher la boîte).
  • Durée de vie : Longue. Les objets restent jusqu'à ce que le Garbage Collector passe nettoyer.
  • Ce qu'on y met : Les gros objets complexes (Types Référence : Class, String, List).
  • Exemple : Vous n'avez pas l'objet sur votre plan de travail, vous avez juste un papier avec son adresse dans l'entrepôt (Pointeur/Référence).

3. Focus sur string : Le Faux Ami

Le type string est un Type Référence (stocké sur la Heap), mais il est immuable (Immutable).

string s = "A";
s += "B"; // CECI NE MODIFIE PAS L'OBJET !
// Cela crée un NOUVEL objet "AB" en mémoire et change le pointeur.
// L'ancien "A" devient un déchet pour le Garbage Collector.

III. La Classe C# : Anatomie Complète

La classe est le plan (blueprint) de vos objets. Analysons sa structure en détail.

public class Sensor
{
    // 1. Champs (Attributs)
    private int _internalId; // Utilisation de l'underscore en préfixe

    // 2. Propriétés (Properties)
    public string Name { get; set; }

    // 3. Constructeur
    public Sensor(int id, string name) { ... }

    // 4. Méthodes
    public void Calibrate() { ... }
}

1. Conventions de Nommage (Standards .NET)

Contrairement au Java ou au Python, C# est très strict sur les conventions pour distinguer ce qui est public de ce qui est privé :

2. Les Champs (Attributes / Fields)

Ce sont les variables déclarées directement dans la classe.

3. Les Propriétés (Properties) : LA notion clé

C'est la différence majeure avec Java ou C++. Une propriété expose une donnée tout en gardant le contrôle (encapsulation). Voici les 4 formats essentiels à connaître :

A. Auto-Implemented Property (Le Standard)

C'est la forme la plus courante (90% des cas). Le compilateur crée le champ privé (backing field) pour vous. Idéal pour les DTOs (Data Transfer Objects).

public string Name { get; set; }
// Read: var n = obj.Name;
// Écriture : obj.Name = "Sonde 1";

B. Full Property (Avec Logique de Validation)

Utilisée quand vous devez contrôler la valeur avant de l'assigner (ex: empêcher une température < -273). Nécessite de déclarer le champ privé manuellement.

private double _value; // Champ de stockage (camelCase avec prefixe _)

public double Value 
{
    get { return _value; }
    set 
    {
        // Le mot clé 'value' représente la donnée entrante
        if (value < -273.15) 
            Console.WriteLine("Erreur physique !"); 
        else 
            _value = value;
    }
}

C. Expression-Bodied Property (Propriété Calculée)

Très puissante en Data Science. Cette propriété ne stocke rien en mémoire. Elle calcule le résultat à la volée à chaque appel. C'est une méthode déguisée en propriété (Lecture seule).

public double Price { get; set; }
public double TaxRate { get; set; }

// Syntaxe '=>' (Expression Lambda)
// Pas de 'set'. La valeur change si Price ou TaxRate changent.
public double TotalCost => Price * (1 + TaxRate);

D. Init-Only Property (Immutability - C# 9+)

Essentiel pour la programmation robuste. Permet de définir la valeur uniquement à la création de l'objet. Ensuite, elle devient lecture seule.

public int Id { get; init; }

// Usage :
var s = new Sensor { Id = 101 }; // OK (Initialisation)
// s.Id = 102; // ERREUR DE COMPILATION ! (Modification interdite)

4. Le Constructeur

Méthode spéciale appelée à l'instanciation (new).

public Sensor(string name)
{
    this.Name = name; // 'this.Name' est la propriété, 'name' est le paramètre
}

5. Les Méthodes

Ce sont les comportements de l'objet. Le nom est toujours en PascalCase.

// Méthode simple (Action)
public void Calibrate()
{
    Console.WriteLine($"Calibrating {Name}...");
    Value = 0.0;
}

// Surcharge (Overloading) : Même nom, signature différente
public void Calibrate(double offset)
{
    Value += offset;
}

// Méthode avec valeur de retour
public bool IsCritical()
{
    return Value > 80.0;
}

IV. Structures de Contrôle & Itérations

1. Les Conditions

A. if / else

Classique, identique au C/C++/Java.

if (temperature > 100) {
    Alert();
} else if (temperature < 0) {
    Freeze();
} else {
    Ok();
}

B. switch (Classique vs Moderne)

C# a considérablement modernisé le switch statement.

// Switch Classique
switch (sensorType)
{
    case "CO2":
        ProcessGas();
        break;
    default:
        ProcessOther();
        break;
}

// Switch Expression (Modern C# - Widely used in Data)
// More concise, returns a value directly.
string category = temperature switch
{
    > 30 => "Hot",
    < 10 => "Cold",
    _    => "Normal" // '_' est le cas par défaut (default)
};

2. Les Structures Itératives (Boucles)

A. The for loop

Utilisée quand on connaît le nombre d'itérations ou qu'on a besoin de l'index i.

for (int i = 0; i < sensors.Count; i++)
{
    Console.WriteLine(sensors[i].Name);
}

B. The while / do-while loop

Utilisée quand la condition d'arrêt dépend d'un état et non d'un compteur.

while (sensor.IsActive())
{
    sensor.ReadData();
}

C. La boucle foreach (La reine des collections)

C'est la boucle la plus utilisée en C#. Elle parcourt n'importe quelle collection (List, Array, etc.) du début à la fin.

var fleet = new List<Sensor>();
// ... remplissage ...

foreach (var s in fleet)
{
    // 's' est une variable locale représentant l'élément courant
    Console.WriteLine(s.Value);
}

V. Synthèse

  1. Mémoire : Distinguez toujours Value Types (petits, rapides, Stack) et Reference Types (Objets, lourds, Heap). Le string est un Reference Type !
  2. Propriétés : N'utilisez plus de champs publics (public int a;). Utilisez toujours des propriétés (public int A { get; set; }) pour respecter l'encapsulation .NET.
  3. Contrôle : Privilégiez foreach pour lire des données et les switch expressions pour catégoriser des valeurs (Data Cleaning).

Chapter 1: .NET Architecture & C# Fundamentals

Module: .NET C# Programming

Level: 4th Year Computer Engineering (Data Science Specialty)

Prerequisite: TP1 (Fundamentals) validated

Introduction

In TP1 (Lab 1), you handled basic syntax to create a simple console application. This chapter aims to formalize this knowledge and "lift the hood": understanding how your C# code is structured, compiled, and managed in memory.

I. From dotnet run to Processor: .NET Architecture

1. The Compilation Pipeline

Unlike C++ (compiled directly into machine code) or Python (interpreted), C# uses a hybrid model:

  1. Source (.cs) → CIL (IL): The Roslyn compiler transforms your code into Common Intermediate Language. It acts as a universal assembly stored in your .dll or .exe file.
  2. CLR (Common Language Runtime): At startup, the runtime loads this IL.
  3. JIT (Just-In-Time): The JIT compiles the IL into native machine code (x64/ARM) on the fly, optimized for the current processor.
Source Code (.cs) Compiler (Roslyn) IL Code (.dll / .exe) CLR & JIT (Native CPU)

Figure 1: The C# Compilation Path

Note: This model ensures that the same binary runs on Windows and Linux while offering performance close to C++ thanks to JIT optimizations.

2. Top-Level Statements

Modern programs (C# 10+) no longer require explicitly writing public static void Main. The code written directly in Program.cs is automatically encapsulated in the Main entry point by the compiler.

II. Basic Types of the .NET System

In C#, everything ultimately inherits from System.Object. For a developer, the critical distinction isn't "text vs number", but Stack vs Heap (Storage Location).

1. Summary Table of Common Types

C# Type .NET Type (CTS) Family (Storage) Usage in Data Science
int System.Int32 Value (Stack) Standard integers (Index, Counters).
long System.Int64 Value (Stack) Large integers (Big Data, DB IDs).
double System.Double Value (Stack) Scientific calculations (IEEE 754 floating point).
decimal System.Decimal Value (Stack) Finance (128 bits, high precision, no rounding errors).
bool System.Boolean Value (Stack) Logic (true/false).
char System.Char Value (Stack) A Unicode character (16 bits).
DateTime System.DateTime Value (Stack) Time management (Struct). Essential for time series.
string System.String Reference (Heap) Text. Warning: Stored as an object (Pointer).

2. Understanding Memory: The "Workbench" vs "Warehouse" Analogy

To simplify, imagine your RAM memory divided into two distinct zones:

🔵 The Stack

This is your "Personal Workbench".

  • Speed: Extremely fast (immediate).
  • Lifespan: Short. When a function ends, the workbench is automatically cleared.
  • What goes in: Simple small tools (Value Types: int, double, bool).
  • Example: A sticky note with the number "42" written on it.

📦 The Heap

This is a distant "Large Warehouse".

  • Speed: Slower (you have to go fetch the box).
  • Lifespan: Long. Objects stay until the Garbage Collector comes to clean up.
  • What goes in: Complex heavy objects (Reference Types: Class, String, List).
  • Example: You don't have the object on your workbench, you just have a paper with its address in the warehouse (Pointer/Reference).

3. Focus on string: The False Friend

The string type is a Reference Type (stored on the Heap), but it is immutable.

string s = "A";
s += "B"; // THIS DOES NOT MODIFY THE OBJECT!
// This creates a NEW object "AB" in memory and changes the pointer.
// The old "A" becomes garbage for the Garbage Collector.

III. The C# Class: Complete Anatomy

The class is the blueprint of your objects. Let's analyze its structure in detail.

public class Sensor
{
    // 1. Fields (Attributes)
    private int _internalId; // Using underscore prefix

    // 2. Properties
    public string Name { get; set; }

    // 3. Constructor
    public Sensor(int id, string name) { ... }

    // 4. Methods
    public void Calibrate() { ... }
}

1. Naming Conventions (.NET Standards)

Unlike Java or Python, C# is very strict about conventions to distinguish public from private members:

2. Fields (Attributes)

These are variables declared directly inside the class.

3. Properties: THE Key Concept

This is the major difference with Java or C++. A property exposes data while keeping control (encapsulation). Here are the 4 essential formats to know:

A. Auto-Implemented Property (The Standard)

This is the most common form (90% of cases). The compiler creates the private field (backing field) for you. Ideal for DTOs (Data Transfer Objects).

public string Name { get; set; }
// Read: var n = obj.Name;
// Write: obj.Name = "Probe 1";

B. Full Property (With Validation Logic)

Used when you need to control the value before assigning it (e.g., preventing a temperature < -273). Requires declaring the private field manually.

private double _value; // Storage field (camelCase with _ prefix)

public double Value 
{
    get { return _value; }
    set 
    {
        // The keyword 'value' represents the incoming data
        if (value < -273.15) 
            Console.WriteLine("Physics Error!"); 
        else 
            _value = value;
    }
}

C. Expression-Bodied Property (Computed Property)

Very powerful in Data Science. This property stores nothing in memory. It calculates the result on the fly at each call. It is a method disguised as a property (Read-only).

public double Price { get; set; }
public double TaxRate { get; set; }

// Syntax '=>' (Lambda Expression)
// No 'set'. Value changes if Price or TaxRate changes.
public double TotalCost => Price * (1 + TaxRate);

D. Init-Only Property (Immutability - C# 9+)

Essential for robust programming. Allows setting the value only at object creation. Afterward, it becomes read-only.

public int Id { get; init; }

// Usage:
var s = new Sensor { Id = 101 }; // OK (Initialization)
// s.Id = 102; // COMPILATION ERROR! (Modification forbidden)

4. The Constructor

Special method called at instantiation (new).

public Sensor(string name)
{
    this.Name = name; // 'this.Name' is the property, 'name' is the parameter
}

5. The Methods

These are the object's behaviors. The name is always in PascalCase.

// Simple Method (Action)
public void Calibrate()
{
    Console.WriteLine($"Calibrating {Name}...");
    Value = 0.0;
}

// Overloading: Same name, different signature
public void Calibrate(double offset)
{
    Value += offset;
}

// Method with return value
public bool IsCritical()
{
    return Value > 80.0;
}

IV. Control Structures & Iterations

1. Conditions

A. if / else

Classic, identical to C/C++/Java.

if (temperature > 100) {
    Alert();
} else if (temperature < 0) {
    Freeze();
} else {
    Ok();
}

B. switch (Classic vs Modern)

C# has significantly modernized the switch statement.

// Switch Classique
switch (sensorType)
{
    case "CO2":
        ProcessGas();
        break;
    default:
        ProcessOther();
        break;
}

// Switch Expression (Modern C# - Widely used in Data)
// More concise, returns a value directly.
string category = temperature switch
{
    > 30 => "Hot",
    < 10 => "Cold",
    _    => "Normal" // '_' is the default case
};

2. Iterative Structures (Loops)

A. The for loop

Used when you know the number of iterations or need the index i.

for (int i = 0; i < sensors.Count; i++)
{
    Console.WriteLine(sensors[i].Name);
}

B. The while / do-while loop

Used when the stop condition depends on a state rather than a counter.

while (sensor.IsActive())
{
    sensor.ReadData();
}

C. The foreach loop (Queen of Collections)

This is the most used loop in C#. It iterates through any collection (List, Array, etc.) from start to finish.

var fleet = new List<Sensor>();
// ... filling ...

foreach (var s in fleet)
{
    // 's' is a local variable representing the current element
    Console.WriteLine(s.Value);
}

V. Summary

  1. Memory: Always distinguish between Value Types (small, fast, Stack) and Reference Types (Objects, heavy, Heap). string is a Reference Type!
  2. Properties: No longer use public fields (public int a;). Always use properties (public int A { get; set; }) to respect .NET encapsulation.
  3. Control: Prefer foreach for reading data and switch expressions for categorizing values (Data Cleaning).