So meistern Sie das C#-Vorstellungsgespräch: Top-Fragen für Fortgeschrittene

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Fortgeschrittenes C#-Vorstellungsgespräch: Wie Sie den Arbeitgeber beeindrucken und nicht durchfallen

\n\n

Ein Vorstellungsgespräch für eine Position als Senior- oder Middle-.NET-Entwickler ist nicht nur eine Überprüfung der Syntax. Interviewer möchten ein tiefes Verständnis der internen Arbeitsweise der Plattform sehen, die Fähigkeit, leistungsfähigen Code zu schreiben und architektonische Entscheidungen zu treffen. In diesem Artikel analysieren wir die wichtigsten Themen und Fragen für Fortgeschrittene, die Ihnen helfen, ein technisches C#-Interview zu bestehen.

\n\n

1. Asynchrone Programmierung: async/await und Task

\n\n

Dies ist wohl das beliebteste Thema in Vorstellungsgesprächen. Es reicht nicht zu sagen, dass Sie async/await kennen. Sie müssen verstehen, wie es unter der Haube funktioniert.

\n\n

Frage: Was ist der SynchronizationContext und wie beeinflusst er die Ausführung von await?

\n

Eine klassische Frage. Der SynchronizationContext ist eine Abstraktion, die es ermöglicht, die Ausführung von Code in einem bestimmten Kontext zu planen (z. B. im UI-Thread von WPF oder im Thread-Pool von ASP.NET). Wenn Sie await verwenden, versucht der Code nach Abschluss des asynchronen Vorgangs standardmäßig, in den ursprünglichen Kontext zurückzukehren. In Konsolenanwendungen ist dies der Thread-Pool, in der UI der Dispatcher-Thread. Das Verständnis dieses Mechanismus hilft, Deadlocks zu vermeiden.

\n\n

Frage: Was ist der Unterschied zwischen Task.Run und Task.Factory.StartNew?

\n

Auf den ersten Blick ähneln sie sich, aber Task.Run ist ein vereinfachter Wrapper. Task.Factory.StartNew bietet mehr Kontrolle (z. B. können Sie TaskCreationOptions oder TaskScheduler festlegen). Standardmäßig verwendet Task.Run jedoch den TaskScheduler.Default (Thread-Pool), während Task.Factory.StartNew den aktuellen Planer verwenden kann, was manchmal zu unerwartetem Verhalten führt.

\n\n
// Beispiel für einen Deadlock aufgrund von SynchronizationContext (in einer UI-Anwendung)\npublic async Task<string> GetDataAsync()\n{\n    var result = await SomeAsyncMethod(); // Kontext erfassen\n    return result.ToString(); // Versucht, in den UI-Thread zurückzukehren\n}\n\n// Wenn .Result oder .Wait() für die Aufgabe aufgerufen wird, entsteht ein Deadlock\nvar data = GetDataAsync().Result; // SCHLECHT!\n
\n\n

2. Speicherverwaltung und Garbage Collector (GC)

\n\n

Ein fortgeschrittener Entwickler muss verstehen, wie .NET den Speicher verwaltet, um Speicherlecks zu vermeiden und die Leistung zu optimieren.

\n\n

Frage: Erklären Sie die GC-Generationen (Gen 0, Gen 1, Gen 2) und den Large Object Heap (LOH).

\n

Der GC in .NET verwendet ein generationsbasiertes Modell. Objekte gelangen zunächst in Gen 0 (häufige Sammlung). Wenn sie eine Sammlung überleben, wechseln sie zu Gen 1, dann zu Gen 2. Der LOH ist für Objekte mit einer Größe von mehr als 85.000 Bytes vorgesehen. Er wird standardmäßig nicht komprimiert (bis .NET 4.5.1), was zu Fragmentierung führen kann. Die Frage kann erweitert werden: "Wie funktioniert die Hintergrund-Garbage-Collection?" oder "Was sind die GC-Modi: Workstation vs. Server?"

\n\n

Frage: Was ist Finalisierung (Finalization) und wie vermeidet man damit verbundene Probleme?

\n

Finalizer (~Finalizer()) verlangsamen die Garbage Collection, da Objekte mit Finalizern in die Finalisierungswarteschlange gelangen und zwei GC-Durchläufe erfordern. Das korrekte Muster ist die Implementierung von IDisposable mit dem Dispose-Muster.

\n\n
public class ResourceHolder : IDisposable\n{\n    private IntPtr _handle;\n    private bool _disposed = false;\n\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n\n    protected virtual void Dispose(bool disposing)\n    {\n        if (!_disposed)\n        {\n            if (disposing)\n            {\n                // Verwaltete Ressourcen freigeben\n            }\n            // Nicht verwaltete Ressourcen freigeben (handle)\n            _disposed = true;\n        }\n    }\n\n    ~ResourceHolder()\n    {\n        Dispose(false);\n    }\n}\n
\n\n

3. Delegaten, Ereignisse und LINQ: Von der Syntax zum Verständnis

\n\n

Diese Themen werden oft

Blogs

Buchempfehlungen