So bestehst du das C#-Vorstellungsgespräch: Top-Fragen für Fortgeschrittene
Ein Vorstellungsgespräch für die Position eines Senior C#-Entwicklers testet nicht nur die Syntaxkenntnisse, sondern auch das tiefe Verständnis der internen Funktionsweise von .NET, der Leistungsoptimierung und architektonischer Entscheidungen. In diesem Artikel analysieren wir die wichtigsten Themen, die häufig in technischen Interviews auftauchen. Du erfährst, wie du auf schwierige Fragen antwortest und erhältst fertige Codebeispiele, um deine Fähigkeiten zu demonstrieren.
1. Asynchrone Programmierung: async/await und Task
Fragen zu async und await sind ein Klassiker in jedem fortgeschrittenen Vorstellungsgespräch. Die Interviewer möchten sehen, dass du verstehst, wie der Synchronisationskontext funktioniert und wie man Deadlocks vermeidet.
Typische Frage: "Was passiert, wenn .Result oder .Wait() in einer asynchronen Methode im UI-Thread aufgerufen wird?"
Antwort: Es entsteht ein Deadlock, da der Hauptthread blockiert wird, während er auf das Ergebnis wartet, und die Fortsetzung (Continuation) der asynchronen Methode versucht, in denselben Synchronisationskontext zurückzukehren, der belegt ist. Die Lösung ist die Verwendung von ConfigureAwait(false) oder ein vollständig asynchroner Aufruf.
public async Task<string> GetDataAsync(){ // Korrekte Arbeit mit dem Kontext var result = await SomeHttpCallAsync().ConfigureAwait(false); return result;}
// Fehler: Deadlock in UI/ASP.NET Core (vor .NET Core 2.1)// var data = GetDataAsync().Result;Zusatzfrage: "Was ist der Unterschied zwischen Task.Run und Task.Factory.StartNew?"
Task.Run verwendet den Standard-Threadpool und entpackt automatisch verschachtelte Tasks. StartNew bietet mehr Kontrolle (z. B. kann TaskCreationOptions.LongRunning angegeben werden), erfordert jedoch die manuelle Verwaltung von Unwrap() für asynchrone Delegaten.
2. LINQ und verzögerte Ausführung (Deferred Execution)
LINQ ist ein mächtiges Werkzeug, aber seine falsche Verwendung kann zu Leistungseinbußen führen. Fortgeschrittene Fragen betreffen oft IQueryable vs. IEnumerable und die Materialisierung von Abfragen.
Frage: "Warum führt der folgende Code mehrere Datenbankabfragen aus?"
var query = context.Products.Where(p => p.Price > 100);foreach (var product in query){ Console.WriteLine(product.Name);}var count = query.Count(); // Zweite Abfrage!Antwort: IQueryable repräsentiert einen Ausdrucksbaum (Expression Tree), der in SQL übersetzt wird. Jedes Mal, wenn du iterierst oder eine Aggregatfunktion (Count, Sum) aufrufst, wird SQL erneut gesendet. Um dies zu vermeiden, müssen die Daten materialisiert werden: var list = query.ToList();
Fortgeschrittener Nuance: Der Unterschied zwischen First() und FirstOrDefault() – First() wirft eine Ausnahme, wenn die Sequenz leer ist, was im Hinblick auf die Fehlerbehandlung teurer sein kann.
3. Speicherverwaltung und Garbage Collector (GC)
Das Verständnis der Funktionsweise des GC ist ein Zeichen für einen Senior-Entwickler. Fragen können sich auf Generationen (Generations), Finalisierung und das Dispose-Pattern beziehen.
Frage: "Was ist der Large Object Heap (LOH) und warum sollte man vorsichtig mit ihm sein?"
Antwort: Der LOH ist ein Heap für Objekte, die größer als 85.000 Bytes sind. Im Gegensatz zum Small Object Heap wird der LOH (bis .NET 4.5.1) nicht kompaktiert, was zu Speicherfragmentierung führt. Dies kann eine OutOfMemoryException auslösen, selbst wenn viel freier Speicher vorhanden ist. Empfehlungen: Objektpools verwenden oder große Arrays in Teile aufteilen.
// Beispiel für eine schlechte Praxisbyte[] largeBuffer = new byte[100_000]; // Landet im LOH
// Besser: ArrayPool verwendenbyte[]