C# bekommt Union Types — und dein Team wird sie erstmal ignorieren
Letzten Herbst saß ich in einem Code-Review bei einem Maschinenbauer aus dem Stuttgarter Raum. 180 Mitarbeitende, solides .NET-Haus, seit Jahren gewachsene Codebasis. Der Entwickler präsentierte eine Methode, die bei Erfolg ein Objekt zurückgab und bei Fehler null. Ich fragte, wie der Aufrufer wissen soll, ob null "nicht gefunden" oder "Datenbankfehler" bedeutet. Stille. Dann: "Man guckt halt in den Logs."
Das ist kein Einzelfall. Das ist der Normalzustand in 70 % der Mittelstands-.NET-Projekte, die ich sehe. Nicht weil die Leute schlecht sind — die meisten sind ordentliche Handwerker — sondern weil C# ihnen jahrelang keine gute Sprache für dieses Problem angeboten hat. Das ändert sich jetzt gerade.
Was Andrew Lock beschreibt
Andrew Lock hat in seinem Artikel einen der langerwarteten Features von C# 15 / .NET 11 aufgedröselt: das neue union-Keyword. Die Kurzversion: Du kannst jetzt einen Typ definieren, der genau eine von mehreren konkreten Typen enthält — typsicher, compiler-enforced, ohne Vererbungshierarchie. Ein klassisches Beispiel ist der Result<T>-Typ, der entweder einen Erfolgswert oder eine Exception enthält. Lock zeigt, wie die Syntax aussieht, wie man mit switch-Expressions exhaustiv darüber matcht und — das ist das Entscheidende — dass der Compiler dich zwingt, alle Fälle zu behandeln. Kein vergessener Fehlerfall mehr. Er geht auch in die Implementierungsdetails: Union Types sind ein Compiler-Feature, laufen also auch auf älteren Runtimes ab .NET 8, wenn du das .NET 11 SDK und <LangVersion>preview</LangVersion> im csproj setzt.
Wie das im KMU wirklich landet
Ich will ehrlich sein: Die Syntax ist elegant. Das union-Keyword ist besser lesbar als alles, was bisher existierte — OneOf-Bibliotheken, handgestrickte Discriminated Unions, Wert-plus-Fehlercode-Tupel. Aber das Feature allein löst das Problem nicht. Das Problem ist kulturell.
Fehler-Signalisierung als Architekturentscheidung fehlt im KMU-Alltag fast immer. In den meisten Teams, mit denen ich arbeite, gibt es keine schriftliche Konvention dazu. Exceptions für alles, null für nichts-gefunden, manchmal bool-Returns für Erfolg/Misserfolg — je nach Entwickler, je nach Tag, je nach wie viel Kaffee. Union Types helfen nur, wenn das Team sich einigt, sie konsequent zu benutzen. Sonst hast du nach sechs Monaten drei Stile im Codebase statt vorher zwei.
Die Lernkurve ist unterschätzt. Ich schätze: Für einen Entwickler mit fünf Jahren C#-Erfahrung und ohne Functional-Programming-Hintergrund dauert es vier bis acht Wochen, bis er Union Types und exhaustive Matches wirklich im Schlaf schreibt. In einem Team mit acht Entwicklern und laufendem Tagesgeschäft bedeutet das realistisch sechs bis zwölf Monate, bis die Nutzung homogen ist. In dieser Zeit leidet Code-Review, weil die Reviewer selbst unsicher sind.
Was sich trotzdem sofort lohnt: Der Result<T>-Typ. Nicht als generisches Pattern über alles, sondern gezielt an API-Grenzen und bei Datenbankzugriffen. Wenn dein Service-Layer in Richtung Frontend oder externe Systeme kommuniziert, ist ein expliziter Result<KundeDto, FehlerTyp> besser als eine Exception-Flut, die irgendwo in einem globalen Handler landet und dem Aufrufer nichts Nützliches zurückgibt. Das ist der Use-Case, für den ich Union Types im Mittelstand sofort einsetzen würde.
Was ich noch nicht im Produktivbetrieb haben will: Union Types als generelles Steuerfluss-Instrument durch alle Layer. Ich habe Teams gesehen, die das Result-Pattern aus den F#- und Rust-Welt importiert haben und danach jeden Methodenaufruf in ein Result<> gewickelt haben — einschließlich interner Hilfsmethoden, die nie fehlschlagen können. Das Ergebnis war mehr Rauschen als Signal. Die Faustregel, die ich meinen Mandaten mitgebe: Union Types an Systemgrenzen ja, innerhalb von Klassen nein.
Die ehrliche Einschätzung für .NET-Teams im Mittelstand
Wenn dein Team heute noch auf .NET 6 oder 8 ist und die nächste Migration nicht vor 2027 geplant ist: Fang jetzt trotzdem an. Das Feature ist Compiler-seitig, läuft auf .NET 8. Du kannst mit <LangVersion>preview</LangVersion> experimentieren, ohne die Runtime anzufassen. Kauf dir damit Zeit, das Team auf das Pattern einzuschwören, bevor .NET 11 LTS ist.
Wenn dein Team schon OneOf oder ein anderes NuGet-Package für Discriminated Unions benutzt: Wechsel nicht sofort. Warte auf .NET 11 GA, schau wie sich das Tooling entwickelt (Resharper, Rider, VS), und plant dann eine kontrollierte Migration. Zwei Muster für dasselbe Problem im gleichen Codebase ist das Schlechteste.
Konkrete Zahl, die ich aus meinen Mandaten kenne: Bei einem Dienstleister mit 12 .NET-Entwicklern haben wir im letzten Jahr das Result-Pattern eingeführt — mit der damals noch notwendigen OneOf-Library. Der Aufwand für Einführung, Code-Review-Guidelines und Team-Coaching: ungefähr 15 Personentage verteilt über vier Monate. Der messbare Effekt: Support-Tickets wegen "unklarem Fehlerzustand aus dem Backend" sind in den sechs Monaten danach um etwa 40 % zurückgegangen. Nicht wegen der Technologie allein, sondern weil das Pattern den Entwicklern zwingt, über Fehlerzustände nachzudenken, bevor sie einen PR öffnen.
Das ist der echte Wert von Union Types. Nicht die Syntax-Eleganz, die Lock sehr schön beschreibt. Sondern dass der Compiler dich anschreit, wenn du vergisst, dass eine Methode auch fehlschlagen kann.
Was im Artikel fehlt — und kein Vorwurf ist
Lock schreibt aus der Perspektive eines erfahrenen .NET-Architekten und Framework-Autors. Das macht seinen Artikel zu einer exzellenten technischen Referenz. Was fehlt, ist die Frage: Wie führe ich das in einem Team ein, das dieses Denkmuster noch nicht hat? Wie verhindern ich, dass Union Types zur Cargo-Cult-Technologie werden — benutzt weil es neu ist, nicht weil es das richtige Werkzeug ist?
Das ist nicht seine Aufgabe. Das ist meine.
Meine Empfehlung: Lies seinen Artikel, um zu verstehen wie es funktioniert. Dann setz dich mit deinem Tech-Lead zusammen und definiert in einem halben Tag, wo ihr Union Types benutzt und wo nicht. Schreibt das in die Contributing-Docs. Dann und nur dann lohnt sich das Feature.
Der vollständige Original-Beitrag von Andrew Lock: .NET (OK, C#) finally gets union types🎉: Exploring the .NET 11 preview - Part 2
Wenn du wissen willst, wie eine saubere Fehlerbehandlungs-Konvention für dein konkretes .NET-Team aussehen kann — ohne sechs Monate Reibung:
— Bernhard