# Neues in C# 13 (20.12.2024) Im November dieses Jahres veröffentlichte Microsoft die neunte Version von .NET. Mit diesem Release kam auch eine neue C# Version, welche wir uns in diesem Blog genauer anschauen wollen: ## Neue Features C# 13, die neue Version, kommt mit vielen neuen Features und Änderungen:[^2] - `params` *Collections* - Ein neuer *lock*-Typ und neue Semantik - Eine neue Escape Sequence (*\e*) - Methoden Gruppe `natural type` wurde verbessert - Impliziter Zugriff auf den *indexer* in der Objekt Initialisierung - `ref local`'s und `unsafe context`'s wurden in Iteratoren und asynchronen Methoden ermöglicht - `ref struct` Typen können *Interfaces* implementieren - `ref struct` Typen können in *Generics* als Argumente übergeben werden - `partial` Eigenschaften und *Indexers* können jetzt in `partial` Typen genutzt werden - *Overload Resolution Priority* Es sind sehr viele Änderungen dazu gekommen und viele dieser behandeln Themen welche für uns nicht interessant sind. Aus diesem Grund werden wir nur über die wichtigsten gehen. ## `params` Collections Bisher war der `params` *modifier* nur mit Array-Typen nutzbar. Mit C# 13 kann dieser auch mit Collection-Typen genutzt werden.[^3] ### `params` Ein `params` Parameter bietet einen einfachen Weg, um eine Methode mit einer willkürlichen Anzahl an Parametern aufzurufen. Angenommen wir haben folgende Methode: ```csharp public static int addOneEach(params int[] nums) { return nums.Sum() + nums.Length; } ``` Um diese Methode jetzt aufzurufen haben wir zwei Möglichkeiten: ```csharp addOneEach(new int[] {1, 2, 3, 4, 5}); ``` Der erste Weg ist über eine Instanz eines Arrays. Da wir jedoch einen `params` Parameter haben, können wir unsere Methode auch einfach so aufrufen: ```csharp addOneEach(1, 2, 3, 4, 5); ``` Wir ersparen uns also die Erstellung eines Arrays bevor wir die Daten übergeben können. In diesem Fall ist die Verwendung von `params` nicht sehr Sinnvoll, es gibt jedoch viele Situationen, in denen die Verwendung zu einer einfacheren Nutzung führen kann. ### Collection-Types Die oben demonstrierte Ausführung von `params` war schon in den früheren Versionen möglich. Man war jedoch auf die Verwendung von Array-Typen beschränkt. Mit der neuen Versionen können jetzt auch Collection-Types verwendet werden. Zu diesen gehören: - `Span` und `ReadOnlySpan` - Alle Typen die `IEnumerable` implementieren und eine `Add` Methode haben - Die Interfaces `IEnumerable`, `IReadOnlyCollection`, `IReadOnlyList`, `ICollection` und `IList` ## Overload Resolution Priority In C# 13 erkennt der Compiler das `[OverloadResolutionPriority]` Attribut um einen Overload über einen anderen zu priorisieren.[^4][^5] ### Overloads Overloads kommen dann vor, wenn eine Methode mit dem gleichen Namen aber einer anderen Signatur erstellt wird: ```csharp public static int PlusNums(int num1, int num2) { return num1 + num2; } public static double PlusNums(double num1, double num2) { return num1 + num2; } ``` In diesem Beispiel haben wir zwei Methoden mit dem gleichen Namen aber unterschiedlicher Signatur. In diesem Fall unterscheidet sich der Typ des Parameter und der Rückgabe. Je nach dem welchen Input wir also geben, wird der passende Overload verwendet: ```csharp var myNum1 = PlusNums(3, 4); // Die erste Implementation wird verwendet var myNum2 = PlusNums(1.2, 4.5); // Die zweite Implementation wird verwendet ``` ### `[OverloadResolutionPriority]` Wie im obigen Beispiel zu sehen ist, wird bei klaren Fällen automatisch die richtige Implementation gewählt. Es gibt jedoch auch fälle in denen keine klare Entscheidung getroffen werden kann. Angenommen wir haben folgende Methoden: ```csharp public static void M(ICollection<int> s) => Console.WriteLine("ICollection"); public static void M(IReadOnlyCollection<int> a) => Console.WriteLine("IReadOnlyCollection"); ``` In diesem Fall kann sich der Compiler nicht für eine Implementation entscheiden und gibt einen Fehler zurück. Mit dem neuen Attribut können wir jedoch eine Implementation wählen welche wir bevorzugen wollen: ```csharp public static void M(ICollection<int> s) => Console.WriteLine("ICollection"); [OverloadResolutionPriority(1)] public static void M(IReadOnlyCollection<int> a) => Console.WriteLine("IReadOnlyCollection"); ``` So würde die zweite Implementation über die erste gewählt werden. Dem Attribut muss immer ein Zahlenwert übergeben werden. Die Standard Priorität ist `0`, eine höhere wird also vom Compiler priorisiert. Man kann jedoch auch einen negativen Wert übergeben um eine tiefere Priorität zu erzwingen. Die Nutzung dieses Attributs sollte jedoch nur in Spezialfällen verwendet werden. ## Fazit Wir haben uns jetzt zwei der grösseren Änderungen in C# 13 angeschaut. Wie am Anfang aufgezählt gibt es jedoch viele weitere, welche alle mit interessanten Möglichkeiten kommen. Auch jetzt arbeitet das Entwickler-Team von C# aktiv an Verbesserungen für die nächste Version. Falls euch interessiert, an was genau gearbeitet wird, könnt ihr im Github Repo von Roslyn (der Compiler welcher auch für C# genutzt wird) vorbei schauen: https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md. [^1]: vgl. .NET and .NET Core Support Policy, in: Microsoft .NET, 11.12.2024, https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core [^2]: vgl. What's new in C# 13, in: Microsoft Learn, 20.12.2024, https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13 [^3]: vgl. params Collections, in: Microsoft Learn, 20.12.2024, https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-13.0/params-collections [^4]: vgl. OverloadResolutionPriorityAttributeClass in: Microsoft .NET, 20.12.2024, https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.overloadresolutionpriorityattribute?view=net-9.0 [^5]: vgl. `OverloadResolutionPriority` attribute, in: Microsoft Learn, 20.12.2024, https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#overloadresolutionpriority-attribute