Seit .NET 5 gibt es in C# ein Sprachfeature, mit dem man Code generieren kann, basierend auf dem C#-Code, der schon da ist.
Das öffnet vielen Dingen die Tore, z. B.:
- Dependency Injection zur Compiletime (statt Runtime); dadurch schnellere Startzeit
- Spezialisierte (JSON-)Serialisierungs-Typen, die genau einen bestimmten Typen (De-)Serialisieren können
- Ganz viel Reflection fällt weg
Eigentlich ist Code-Generation gar nicht so toll. Man hat am Ende Zeug, das man nicht ordentlich debuggen kann und im Zweifelsfall ist der Fehler im Code-Generator. Sowas ist auch immer ein Zeichen dafür, dass die Sprache nicht ausdrucksstark genug ist.
Außerdem habe ich bisher schlechte Erfahrungen damit gemacht (ok, eigentlich nur in Java). Da hat man immer mal wieder das Problem, dass generierter Code (z. B. von immutables.org) “noch nicht da ist” und die IDE dann meckert, warum man eine nicht-existente Klasse verwendet (in diesem Fall z. B. der Builder für einen unveränderlichen Typen).
Man sieht aber trotzdem den Use-Case für solche Dinge. Da C# sich aktuell stark darauf hinentwickelt, Ahead-Of-Time-Compile-fähig zu sein, ergibt dieses Feature Sinn. Z.B. ist Reflection bei AOT-Kompilierung ein Dorn im Auge, da man nicht weiß, welche Typen/Codeteile man aus der fertigen Assembly rausschmeißen kann. Man kann außerdem sehr schön optimieren, wenn man konkreten Code mit ordentlichen Typen statt Reflection hat.
Vermutlich werden viele Dinge, die C# vor ein paar Jahren noch als eigenes Feature gebaut hätte, jetzt als Source-Generator implementiert. Letztendlich ist das ja auch nur ein Compiler-Plugin, das Lowering betreibt. Hoffentlich wird es die Sprache nicht allzu krass verwässern. Die Befürchtung habe ich ja schon.
Hier ist eine Liste mit Source-Generatoren, die man sich in einer freien Minute anschauen kann. Viel Zeug dabei, das man nicht braucht. Aber auch viel nützliches.