Introduction
\nUn entretien pour un poste de développeur C# ne se limite pas à une simple vérification de la syntaxe. Les employeurs veulent voir une compréhension de la plateforme .NET, des principes de fonctionnement du CLR, la capacité à écrire du code performant et la connaissance des approches modernes (async, LINQ, DI).
\nDans cet article, nous analyserons les meilleures questions sur C# de A à Z — des types de données de base aux sujets complexes comme le garbage collection et la programmation asynchrone. Chaque question est accompagnée d'une réponse concise et d'un exemple de code pour vous sentir confiant lors de l'entretien.
\n\n1. Questions de base : types, classes et mémoire
\n\n1.1. Quelle est la différence entre Value Type et Reference Type ?
\nValue Type (int, struct, enum) sont stockés dans la pile et copiés par valeur. Reference Type (class, string, array) sont stockés dans le tas, la variable contient une référence vers l'objet.
\nint a = 10;\nint b = a; // b est une copie, a et b sont indépendants\n\nclass MyClass { public int X; }\nMyClass obj1 = new MyClass { X = 5 };\nMyClass obj2 = obj1; // obj2 référence le même objet\nobj2.X = 10; // obj1.X devient également 10\n\n1.2. Qu'est-ce que le Boxing et l'Unboxing ?
\nBoxing — empaquetage d'un type valeur dans un objet (dans le tas). Unboxing — processus inverse. Une utilisation fréquente réduit les performances.
\nint number = 42;\nobject boxed = number; // Boxing\nint unboxed = (int)boxed; // Unboxing\n\n1.3. Parlez-moi du Garbage Collector.
\nLe GC dans .NET libère automatiquement la mémoire des objets qui n'ont plus de références. Il fonctionne par générations (Gen 0, 1, 2). Les objets de grande taille (>85 Ko) sont placés dans le Large Object Heap (LOH).
\nConseil : N'appelez pas GC.Collect() manuellement — cela perturbe les optimisations du GC.
2. POO et principes de conception
\n\n2.1. Expliquez les principes SOLID.
\n- \n
- S — Single Responsibility : une classe doit avoir une seule raison de changer. \n
- O — Open/Closed : ouverte à l'extension, fermée à la modification. \n
- L — Liskov Substitution : les sous-classes doivent pouvoir remplacer correctement la classe de base. \n
- I — Interface Segregation : plusieurs petites interfaces valent mieux qu'une grande. \n
- D — Dependency Inversion : les dépendances doivent être dirigées vers des abstractions, non vers des classes concrètes. \n
2.2. Qu'est-ce que l'Injection de Dépendances (DI) ?
\nDI — un patron où les dépendances sont transmises à la classe de l'extérieur (via le constructeur, une méthode ou une propriété). Dans .NET Core, un conteneur DI intégré est disponible.
\npublic interface ILogger\n{\n void Log(string message);\n}\n\npublic class ConsoleLogger : ILogger\n{\n public void Log(string message) => Console.WriteLine(message);\n}\n\npublic class OrderService\n{\n private readonly ILogger _logger;\n public OrderService(ILogger logger) // DI via le constructeur\n {\n _logger = logger;\n }\n}\n\n3. LINQ, exceptions et chaînes de caractères
\n\n3.1. Comment fonctionne LINQ ? Qu'est-ce que l'exécution différée ?
\nLINQ (Language Integrated Query) permet d'écrire des requêtes sur des collections, des bases de données (EF Core) et du XML. L'exécution différée signifie que la requête n'est exécutée que lors de l'itération du résultat (par exemple, via foreach ou .ToList()).
var numbers = new List<int> { 1, 2, 3, 4, 5 };\nvar query = numbers.Where(n => n > 2); // la requête n'est pas exécutée\nnumbers.Add(6); // ajout après la création de la requête\nforeach (var n in query) // exécution ici\n Console.WriteLine(n); // 3, 4, 5, 6\n\n3.2. Quelle est la différence entre String et StringBuilder ?
\nString — type immuable. Chaque opération de concaténation crée un nouvel objet. StringBuilder utilise un tampon mutable et est efficace pour les modifications multiples d'une chaîne.
\n// Mauvais (nombreuses allocations)\nstring s = "";\nfor (int i = 0; i < 1000; i++)\n s += i.ToString(); // crée 1000 nouveaux objets\n\n// Bon (efficace)\nStringBuilder sb = new StringBuilder();\nfor (int i = 0; i < 1000; i++)\n sb.Append(i); // utilise un seul tampon