Einleitung: Die Legende vom „toten“ C#
Sie haben sicherlich gehört, dass C# eine Sprache für „Konzernleute“ sei, wo alles langweilig, langsam und von einer Schicht Enterprise-Bürokratie überzogen ist. Aber die Wahrheit ist, dass ein C#-Entwickler heute ein universeller IT-Soldat ist. Er schreibt schnelle Microservices mit ASP.NET Core, optimiert Datenbankabfragen mit Entity Framework und integriert manchmal sogar maschinelles Lernen mit ML.NET.
In diesem Artikel werde ich keine abstrakten Theorien erzählen. Wir gehen einen typischen Arbeitstag eines C#-Programmierers in einem echten Unternehmen durch: vom Morgenkaffee bis zum Push des Codes in die Produktion. Sie sehen Codebeispiele, Werkzeuge und Lifehacks, die Ihnen Stunden Arbeit sparen.
08:30 — Morgen: Kaffee, E-Mail und Aufgabenboard
Der Tag beginnt nicht mit Code, sondern mit Kontext. Als Erstes öffne ich Slack und Jira. In einem typischen Team gibt es ein morgendliches Standup (daily stand-up). Dort beantworten wir drei Fragen:
- Was wurde gestern erledigt?
- Was werde ich heute tun?
- Gibt es Blockaden?
Nach dem Standup folgt ein kurzer Überblick über die Pull-Requests der Kollegen. Code-Review in C# ist nicht nur ein „Häkchen“. Hier ist es wichtig zu prüfen, ob es Speicherlecks gibt (insbesondere mit IDisposable) und ob async/await korrekt verwendet wird.
Beispiel aus der Praxis: Code-Review einer asynchronen Methode
// Schlecht: Blockierender Aufruf innerhalb einer async-Methodepublic async Task<User> GetUserAsync(int id){ var user = _context.Users.Find(id); // .Find — synchron! return await Task.FromResult(user); // Sinnloser Wrapper}
// Gut: Vollständig asynchronpublic async Task<User> GetUserAsync(int id){ return await _context.Users.FindAsync(id); // Echte Asynchronität}Eine solche Kleinigkeit kann die Leistung unter Last zerstören. Daher muss ein C#-Programmierer bei jedem Schritt auf die Asynchronität achten.
10:00 — Arbeit an der Aufgabe: Einen neuen API-Endpunkt schreiben
Heute steht im Backlog die Aufgabe „Filterung von Produkten nach Preis hinzufügen“. Das ist eine typische Geschichte für einen .NET-Entwickler. Ich arbeite in Visual Studio 2022 mit ReSharper (ja, es ist langsam, aber ohne geht es nicht).
Schritt 1: Modell und DTO
Zuerst definieren wir das Datenmodell. Nehmen wir an, wir haben Entity Framework Core und eine PostgreSQL-Datenbank.
public class Product{ public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Category { get; set; }}
public class ProductFilterDto{ public decimal? MinPrice { get; set; } public decimal? MaxPrice { get; set; } public string? Category { get; set; }}Schritt 2: Repository mit IQueryable
Der wichtigste Trick ist, nicht alle Daten in den Speicher zu laden, sondern IQueryable zu verwenden. Dadurch kann die SQL-Abfrage auf der Datenbankseite formuliert werden.
public async Task<List<Product>> GetFilteredProductsAsync(ProductFilterDto filter){ var query = _context.Products.AsQueryable();
if (filter.MinPrice.HasValue) query = query.Where(p => p.Price >= filter.MinPrice.Value);
if (filter.MaxPrice.HasValue) query = query.Where(p => p.Price <= filter.MaxPrice.Value);
if (!string.IsNullOrEmpty(filter.Category)) query = query.Where(p => p.Category == filter.Category);
return await query.ToListAsync();}Beachten Sie: Wir rufen .ToList() erst ganz am Ende auf. Das ist ein grundlegendes, aber kritisch wichtiges Muster für jeden C#-Entwickler.
Schritt 3: ASP.NET Core Controller
[ApiController][Route("api/[controller]")]public class ProductsController : ControllerBase{ private readonly IProductRepository _repo;
public ProductsController(IProductRepository repo) =&g