mercredi 8 octobre 2025

Q/A Bibliothèque .NET



🔹 1. Quelle est la différence entre .NET Framework, .NET Core et .NET (5 et supérieur) ?

Plateforme Période Compatibilité OS supportés Objectif
.NET Framework 2002 → 2019 Windows uniquement Windows Ancien framework historique (.NET 4.x)
.NET Core 2016 → 2020 Cross-platform Windows, Linux, macOS Léger, open source, plus rapide
.NET (5, 6, 7, 8...) 2020 → présent Unifié Cross-platform Fusion de .NET Core et Framework

✅ Exemple :

  • .NET Framework : applications WinForms, WPF, ASP.NET MVC classiques.

  • .NET Core : microservices, API REST, containers Docker.

  • .NET 8+ : unification (Web, Desktop, MAUI, Cloud, etc.).

🧠 Résumé :

.NET 5+ est la plateforme unifiée, performante et multiplateforme, héritière de .NET Core.
.NET Framework est legacy, toujours utilisé dans les grandes entreprises.


🔹 2. Qu'est-ce que le Garbage Collector et comment fonctionne-t-il en .NET ?

Le Garbage Collector (GC) est le système de gestion automatique de la mémoire en .NET.
Il libère la mémoire des objets inaccessibles (non référencés).

✅ Fonctionnement :

  1. Le CLR alloue les objets dans le heap managé.

  2. Le GC s’exécute quand :

    • la mémoire est faible ;

    • le heap atteint un seuil critique ;

    • ou explicitement via GC.Collect() (rarement recommandé).

  3. Il marque les objets accessibles (“mark”), compacte le heap (“compact”), et libère les autres (“sweep”).

✅ Générations :

  • Gen 0 : objets très récents (collectés souvent)

  • Gen 1 : objets intermédiaires

  • Gen 2 : objets persistants (collectés rarement)

Exemple :

var person = new Person("Alice");
// Quand "person" sort de portée → GC peut libérer la mémoire

🧠 Résumé :

Le GC optimise l’utilisation mémoire sans intervention explicite du développeur, mais on peut le contrôler indirectement via IDisposable ou using.


🔹 3. Différences entre List, Array et ArrayList

Type Générique Taille Performance Type-sûr Utilisation
Array Non Fixe Très rapide ✅ Oui Données de taille connue
List ✅ Oui Dynamique Très rapide ✅ Oui Collections dynamiques typées
ArrayList ❌ Non Dynamique Moins rapide (boxing/unboxing) ❌ Non Ancien, avant les génériques (pré-.NET 2.0)

Exemple :

int[] arr = new int[3] { 1, 2, 3 };
List<int> list = new List<int>() { 1, 2, 3 };
ArrayList al = new ArrayList() { 1, "two", 3.0 }; // hétérogène

🧠 Résumé :

Utilisez toujours List<T> (ou ObservableCollection<T> / ImmutableList<T> selon le besoin).
ArrayList est obsolète.


🔹 4. Comment fonctionne la gestion de mémoire dans .NET ?

✅ Types de mémoire :

  • Stack (pile) → stockage des variables locales et des types valeur.

    • Allocation/désallocation très rapide.

  • Heap managé → stockage des types référence (objets).

    • Géré par le Garbage Collector.

✅ Cycle de vie :

  1. Allocation automatique (new).

  2. Références utilisées pendant l’exécution.

  3. Quand plus référencées → GC les supprime.

  4. Ressources non managées doivent être libérées manuellement (Dispose).

Exemple :

void Example()
{
    int x = 5;              // stack
    var p = new Person();   // heap
} // p devient éligible pour le GC

🧠 Résumé :

Le CLR gère automatiquement la mémoire managée, mais les ressources non managées nécessitent une libération manuelle (IDisposable).


🔹 5. Quelles sont les principales classes de System.IO pour la gestion des fichiers ?

Classe Rôle Exemple
File / FileInfo Manipulation de fichiers (création, suppression, lecture, etc.) File.ReadAllText(path)
Directory / DirectoryInfo Manipulation de dossiers Directory.CreateDirectory(path)
FileStream Lecture/écriture bas niveau (flux d’octets) new FileStream(path, FileMode.Open)
StreamReader / StreamWriter Lecture/écriture texte new StreamReader(path)
BinaryReader / BinaryWriter Lecture/écriture binaire new BinaryWriter(stream)
Path Gestion des chemins Path.Combine(dir, file)

Exemple :

using (var writer = new StreamWriter("data.txt"))
{
    writer.WriteLine("Hello .NET");
}

string content = File.ReadAllText("data.txt");

🧠 Résumé :

System.IO fournit une API complète pour manipuler fichiers, flux, et répertoires à tous les niveaux (haut et bas).


🔹 6. Qu'est-ce que Reflection en C# et comment l’utiliser ?

Reflection permet d’examiner ou de manipuler le métadonnées et les types à l’exécution.

✅ Usages :

  • Chargement dynamique d’assemblies.

  • Inspection des classes, propriétés, méthodes, attributs.

  • Invocation dynamique (sans connaître le type à la compilation).

Exemple :

Type type = typeof(Person);
Console.WriteLine(type.FullName);

foreach (var prop in type.GetProperties())
    Console.WriteLine(prop.Name);

// Invocation dynamique
object obj = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("SayHello");
method.Invoke(obj, null);

🧠 Résumé :

Reflection = introspection dynamique des types.
⚠️ À utiliser avec précaution (plus lent, moins sûr).


🔹 7. Différence entre Struct et Class en C#

Caractéristique struct class
Type Valeur Référence
Allocation Stack Heap
Héritage Pas d’héritage (sauf interfaces) Oui
Nullabilité Non-nullable (sauf Nullable<T>) Oui
Performance Léger, pas de GC Plus lourd, managé
Usage typique Petits objets immuables (ex: Point, DateTime) Entités complexes

Exemple :

struct Point { public int X, Y; }
class Person { public string Name; }

🧠 Résumé :

Utilisez struct pour des petits objets immuables, class pour des objets riches et complexes.


🔹 8. Comment fonctionne le Dispose pattern avec IDisposable ?

Le Dispose Pattern permet de libérer les ressources non managées (fichiers, connexions, flux…).

✅ Interface :

public interface IDisposable
{
    void Dispose();
}

✅ Exemple :

public class FileHandler : IDisposable
{
    private FileStream _stream;

    public FileHandler(string path)
    {
        _stream = new FileStream(path, FileMode.Open);
    }

    public void Dispose()
    {
        _stream?.Dispose();
        GC.SuppressFinalize(this); // empêche le GC d’appeler le finalizer
    }
}

✅ Utilisation :

using (var handler = new FileHandler("data.txt"))
{
    // traitement
} // Dispose() automatiquement appelé

🧠 Résumé :

Dispose = nettoyage explicite.
using = exécution automatique du Dispose() même en cas d’exception.


🔹 9. Différence entre dynamic et var

Mot-clé Type déterminé Vérifié à Utilisation typique
var À la compilation Compilation Typage implicite, mais fortement typé
dynamic À l’exécution Exécution Liaison tardive (interop COM, JSON, reflection)

Exemple :

var x = 10;         // int
dynamic y = 10;     // type inconnu jusqu’à l’exécution

x = "text";  // ❌ Erreur compile-time
y = "text";  // ✅ OK, runtime

🧠 Résumé :

var = compile-time typing (sécurité, performance).
dynamic = runtime typing (flexibilité, moins sûr).


🔹 10. Qu'est-ce qu’un Tuple en C# et quand l’utiliser ?

Un Tuple regroupe plusieurs valeurs sans créer une classe dédiée.

✅ Exemple :

var person = Tuple.Create("Alice", 25);
Console.WriteLine($"{person.Item1}, {person.Item2}");

Depuis C# 7, on préfère les ValueTuple :

(string Name, int Age) person = ("Bob", 30);
Console.WriteLine($"{person.Name}, {person.Age}");

✅ Utilisation typique :

  • Retourner plusieurs valeurs depuis une méthode :

(string name, int age) GetPerson() => ("Tom", 40);
var (n, a) = GetPerson();

🧠 Résumé :

Tuple/ValueTuple = pratique pour des retours multiples ou temporaires,
mais pour des modèles riches → créer une classe ou record.


📘 Synthèse rapide

Thème Résumé
.NET Framework/Core/5+ .NET 5+ = plateforme unifiée et cross-platform
Garbage Collector Nettoie la mémoire des objets non référencés
List vs Array List<T> = collection dynamique typée
Mémoire Stack (rapide) vs Heap (managé par GC)
System.IO File, Directory, FileStream, StreamReader...
Reflection Inspection et invocation dynamique de types
Struct vs Class Valeur vs Référence
IDisposable Libère les ressources non managées
dynamic vs var Liaison tardive vs typage implicite
Tuple Regroupe plusieurs valeurs sans classe dédiée




⚙️ 1. Différence entre Span et Array en termes de performance et d’utilisation

Array<T>

  • Structure de données classique stockée sur le tas (heap).

  • Accès rapide, mais implique souvent des allocations mémoire et du ramassage (GC).

  • Ne peut pas référencer une portion d’un tableau sans copier.

Span<T>

  • Type stack-only (ref struct) introduit avec .NET Core.

  • Permet de manipuler une vue sur une portion de mémoire (tableau, segment de chaîne, buffer) sans allocation ni copie.

  • Travaille sur la pile (stack) → très performant, pas de GC.

🧩 Exemple :

int[] data = { 1, 2, 3, 4, 5 };
Span<int> slice = data.AsSpan(1, 3); // [2, 3, 4]
slice[0] = 99; // Modifie aussi le tableau original

🧠 Résumé :

Type Allocation Peut être sur stack Copie nécessaire Usage
Array<T> Heap Oui pour sous-tableaux Données générales
Span<T> Stack Non Performance, buffers, slices mémoire

⚙️ 2. Comment fonctionne Memory et comment l’utiliser pour éviter les allocations inutiles

Memory<T> :

  • Similaire à Span<T>, mais pouvant être stocké sur le heap (donc utilisable en async).

  • Utilisé pour référencer sans copier une portion de mémoire, mais plus flexible que Span<T>.

🧩 Exemple :

Memory<int> memory = new int[] { 1, 2, 3, 4, 5 };
Memory<int> subMemory = memory.Slice(1, 3);

int first = subMemory.Span[0]; // 2

⚙️ Utilisation typique :

  • Manipulation de buffers ou streams sans recréer des tableaux intermédiaires.

  • Dans des API asynchrones, où Span<T> n’est pas utilisable (ref struct non stockable).

🧠 Résumé :

Memory<T> = version "asynchrone et persistable" de Span<T>.


⚙️ 3. Différences entre JsonSerializer (System.Text.Json) et Newtonsoft.Json

Critère System.Text.Json Newtonsoft.Json
Performance ⚡ Très rapide (allocations faibles) Moins rapide
Allocation mémoire Faible Plus élevée
Null handling Moins flexible Très complet
Polymorphisme Support limité (avant .NET 7) Très bon support
Configuration Moins riche Très complète (JsonConverters, attributes, etc.)
Inclusion dans .NET Oui (lib native) Non (package externe)

🧩 Exemple :

var json = JsonSerializer.Serialize(obj);
var obj2 = JsonSerializer.Deserialize<MyClass>(json);

🧠 Résumé :

System.Text.Json = rapide, moderne, intégré ;
Newtonsoft.Json = plus complet et mature pour les cas complexes.


⚙️ 4. Qu’est-ce qu’un record en C# et pourquoi est-il utile ?

✅ Définition :

Un record est un type référence immuable conçu pour les objets de données (DTO, modèles métier).
Il implémente automatiquement :

  • Equals() / GetHashCode() basés sur les valeurs

  • ToString() lisible

  • Un constructeur de déconstruction

🧩 Exemple :

public record Person(string Name, int Age);

var p1 = new Person("Alice", 30);
var p2 = p1 with { Age = 31 }; // Crée une nouvelle instance

🧠 Avantages :

  • Immutabilité native

  • Comparaison par valeur

  • Syntaxe compacte et lisible


⚙️ 5. Différence entre Task et ValueTask en termes de performance

Type Allocation Recyclable Cas d’usage
Task Toujours alloue un objet Réutilisable via cache du pool Asynchrones généraux
ValueTask Peut éviter une allocation Non réutilisable Méthodes très courtes / souvent synchrones

🧩 Exemple :

async ValueTask<int> GetNumberAsync()
{
    return 42; // Pas d’allocation de Task ici
}

🧠 Résumé :

ValueTask = optimisation micro-performante quand la tâche est souvent déjà complétée.
Sinon, Task reste la norme.


⚙️ 6. Qu’est-ce que Lazy et comment l’utiliser correctement ?

✅ Objectif :

Initialiser un objet uniquement à la première utilisation, de manière thread-safe.

🧩 Exemple :

Lazy<HeavyObject> lazyObj = new Lazy<HeavyObject>(() => new HeavyObject());

var obj = lazyObj.Value; // Instantiation ici seulement

⚙️ Avantages :

  • Délaye la création d’objets coûteux (base de données, cache)

  • Thread-safe par défaut (LazyThreadSafetyMode.ExecutionAndPublication)

🧠 Résumé :

Lazy<T> = initialisation à la demande + thread-safe.


⚙️ 7. Fonctionnement des Ref Structs et pourquoi elles sont utilisées

✅ Définition :

ref struct = structure forcée à rester sur la pile (stack).
Impossible :

  • De la boxer

  • De la stocker sur le heap

  • De l’utiliser dans une closure ou une tâche async

🧩 Exemple :

ref struct MySpanWrapper
{
    public Span<int> Data;
    public MySpanWrapper(Span<int> data) => Data = data;
}

🧠 Utilité :

  • Sécurité mémoire et performance

  • Utilisé par Span<T>, ReadOnlySpan<T>, stackalloc


⚙️ 8. Qu’est-ce que le Garbage Collector Generation 0, 1, 2 et comment cela affecte les performances ?

✅ Le GC en .NET est générationnel :

  • Les objets sont classés selon leur durée de vie estimée.

Génération Description Exemple d’objet
Gen 0 Objets récents, ramassés très souvent Variables locales, petits tableaux
Gen 1 Objets survivants de Gen 0 Buffers réutilisés
Gen 2 Objets de longue durée Singletons, caches, gros objets

⚙️ Fonctionnement :

  • Le GC collecte d’abord Gen 0, puis Gen 1, et plus rarement Gen 2.

  • Moins un objet est collecté, plus il monte de génération.

🧠 Optimisation :

  • Réduire les allocations temporaires (éviter la pression GC)

  • Réutiliser les objets longs (ex : ArrayPool<T>)


⚙️ 9. Comment fonctionne Span.Slice() et pourquoi est-il efficace ?

✅ Fonctionnement :

Slice() crée une vue (window) sur une partie du buffer sans copier les données.

🧩 Exemple :

Span<byte> buffer = stackalloc byte[10];
Span<byte> slice = buffer.Slice(2, 5);

➡️ slice pointe sur la même mémoire, mais avec des bornes différentes.

⚙️ Performance :

  • Aucune allocation

  • Pas de duplication

  • Idéal pour le parsing binaire, manipulation de buffers, etc.

🧠 Résumé :

Slice() = sous-vue mémoire ultra-rapide sans copie ni GC.


⚙️ 10. Différence entre Assembly.Load() et Assembly.LoadFrom()

Méthode Source Contexte de chargement Cas d’usage
Assembly.Load() Nom fort (AssemblyName) Default Load Context Charger un assembly déjà connu du runtime
Assembly.LoadFrom() Chemin complet du fichier DLL LoadFrom context (spécifique) Charger dynamiquement un fichier externe

🧩 Exemple :

var asm1 = Assembly.Load("MyLibrary");
var asm2 = Assembly.LoadFrom(@"C:\libs\MyLibrary.dll");

⚠️ Attention :

  • LoadFrom() peut charger plusieurs copies du même assembly s’il est dans des chemins différents → erreurs de type mismatch.

  • Load() est plus sûr quand l’assembly est référencé ou dans le GAC.

🧠 Résumé :

Load() = pour assemblies connus,
LoadFrom() = pour plugins ou chargements dynamiques.


📘 SYNTHÈSE COMPLÈTE

Concept Description Performance
Span<T> Vue stack-only sur mémoire ⚡ Très haute
Memory<T> Vue heap-safe, async compatible ⚡ Haute
JsonSerializer vs Newtonsoft.Json Nouveau moteur JSON vs historique 🟢 Intégré et rapide
record Type immuable à comparaison par valeur 🔒 Lisible et sûr
ValueTask Moins d’allocations que Task ⚡ Micro-optimisation
Lazy<T> Initialisation à la demande 💡 Thread-safe
ref struct Structure stack-only (Span, ReadOnlySpan) ⚡ Très rapide
GC Generations Cycle de vie objets (Gen0-2) ⚙️ Optimisation mémoire
Slice() Sous-vue sur mémoire sans copie ⚡ Ultra performant
Assembly.LoadFrom() Chargement dynamique depuis fichier ⚠️ À utiliser prudemment


Aucun commentaire:

Enregistrer un commentaire

Q/A Bibliothèque .NET Lượt xem: