Microsoft hat .NET 10 veröffentlicht, eine Version mit Langzeitunterstützung (LTS), die bis zum 10. November 2028 unterstützt wird. Die Plattform erhielt in jeder Komponente bedeutende Leistungsverbesserungen: von der Laufzeitumgebung und den Programmiersprachen über die Systembibliotheken bis hin zu den Build-Tools.
Microsoft empfiehlt Entwicklern zudem, auf .NET 10 umzusteigen, um die Ausführungsgeschwindigkeit zu erhöhen und den Energieverbrauch ihrer Anwendungen zu senken. Zur Erleichterung der Migration kann GitHub Copilot eingesetzt werden, der bei der Anpassung des vorhandenen Codes und der Aktualisierung von Abhängigkeiten hilft.
Das Erscheinen von .NET 10 brachte zwar keine Revolution, aber eine Vielzahl gezielter, ausgereifter Verbesserungen. Das Entwicklungsteam der Plattform hat eindeutig einen Kurs in Richtung „Feinschliff“ eingeschlagen: weniger experimentelle Features, dafür mehr Leistung, Komfort und saubere APIs. In diesem Artikel analysieren wir die wichtigsten Neuerungen.
Die neue Version der Sprache macht die Syntax flexibler, ohne dass die Lesbarkeit darunter leidet.
Eigenschaften mit field. Jetzt ist es möglich, benutzerdefinierte get/set zu schreiben, die über das kontextabhängige Schlüsselwort field auf das Hintergrundfeld zugreifen. Keine manuellen, überflüssigen Felder mehr.
public string Name { get => field; set => field = value.Trim(); }
Ab C# 14 kann das Argument von nameof ein ungebundener generischer Typ sein. Zum Beispiel ergibt nameof(List<>) den Wert List. In früheren C#-Versionen konnten für die Rückgabe des Namens von List<int> nur geschlossene generische Typen wie List verwendet werden.
Diese Änderung trägt dazu bei, den Code mit geringerem Aufwand zu optimieren. C# unterstützt nun mehr implizite Konvertierungen, um die Arbeit mit Span im Entwicklungsalltag angenehmer zu gestalten.
Span ist ein Typ, der eine effiziente Speicherverwaltung ermöglicht. Man erstellt quasi ein „Fenster“, durch das man mit dem Speicher interagiert. Außerdem verhindert Span das Überschreiten der Grenzen des zugewiesenen Speicher-„Fensters“, wie es bei unsicheren Speicherzugriffen passieren könnte. Span führt selbst eine Prüfung durch und gibt einen Fehler aus, wenn ein Index außerhalb der Grenzen liegt.
C# 14 erkennt die Beziehung und unterstützt bestimmte Konvertierungen zwischen ReadOnlySpan<T>, Span<T> und T[]. Span-Typen können als Empfänger von Erweiterungsmethoden auftreten, sich mit anderen Konvertierungen kombinieren und in Situationen bei der Typparameterableitung hilfreich sein.
Parameter wie ref, in und out können nun auch in kurzen Lambdas angegeben werden:
var tryParse = (ref int x) => int.TryParse("42", out x);
Diese Neuerung ermöglicht es uns, uns auf die Codeentwicklung zu konzentrieren, anstatt wiederholt Standardprozeduren beschreiben zu müssen. Besonders relevant wird dies bei out-Parametern sein.
Bereits C# 13 erlaubte die Verwendung von partial für Eigenschaften und Indexer. In der neuen Version kann partial nun zur Aufteilung von Konstruktoren und Ereignissen verwendet werden.
Den größten Nutzen aus den partial-Funktionen werden Bibliotheksentwickler und Ersteller von Codegenerierungstools ziehen. Partielle Ereignisse erweisen sich besonders für Bibliotheken als nützlich, die schwache Ereignisse unterstützen, und partielle Konstruktoren für Plattformen, die kompatiblen Code generieren.
Wichtig ist, dass partielle Konstruktoren und Ereignisse im Gegensatz zu Methoden (die nur deklariert werden können) eine vollständige Implementierung besitzen müssen.
Dies ist eine Optimierungsfunktion, die die Möglichkeiten der Operatorüberladung in der Programmiersprache erweitert. Sie erlaubt es, nicht nur unäre und binäre Operatoren, sondern auch zusammengesetzte Operatoren wie +=, *= und andere zu überladen. Da die Implementierung dieser Operatoren viele Gemeinsamkeiten aufweist, wird im folgenden Text der Operator += betrachtet. Die daraus gezogenen Schlussfolgerungen gelten jedoch auch für die analogen Operatoren.
Wichtig ist, dass bei der Verwendung des Operators += in der Sprache C# 13 zuerst der Aufruf des überladenen Operators + erfolgt und anschließend die Zuweisung des Ergebnisses stattfindet.
Bei der Arbeit mit Werttypen führt die Überladung des Operators + zu einer zusätzlichen Kopie beider Operanden und der Erstellung einer neuen Instanz als Ergebnis. Obwohl dieses Verhalten erwartet wird, kann es zu ungerechtfertigtem Mehraufwand beim Kopieren und Verarbeiten von Daten führen, insbesondere bei der Arbeit mit großen Typen wie mathematischen Vektoren und Tensoren.
Es ist nicht länger nötig, ein DateOnly nur für die Wochennummer in ein DateTime zu konvertieren – dies ist relevant für Geschäftsanwendungen mit intensiver Datumsverarbeitung.
public static class ISOWeek { public static int GetWeekOfYear(DateOnly date); public static int GetYear(DateOnly date); public static DateOnly ToDateOnly(int year, int week, DayOfWeek dayOfWeek); }
Der Aktualisierungsmodus für Archive lädt nicht mehr alles in den Arbeitsspeicher. Das Entpacken erfolgt parallel. Besonders bemerkbar macht sich dies bei großen ZIP-Dateien.
Die Suche nach Zertifikaten anhand des Fingerabdrucks ist dank der neuen Methode FindByThumbprint sicherer geworden. Sie erlaubt es, explizit einen modernen Hash-Algorithmus (z. B. SHA-256) anzugeben und verzichtet auf das veraltete SHA-1.
Die Verarbeitung von PEM-Dateien wurde für die Arbeit mit Byte-Darstellungen von UTF-8 optimiert. Die neue Methode PemEncoding.FindUtf8 macht die Notwendigkeit überflüssig, Bytes in Strings umzuwandeln, was den Speicherverbrauch reduziert und das Parsen beschleunigt.
// Vor .NET 10 byte[] fileContents = File.ReadAllBytes(path); char[] text = Encoding.ASCII.GetString(fileContents); PemFields pemFields = PemEncoding.Find(text); // .NET 10 byte[] fileContents = File.ReadAllBytes(path); PemFields pemFields = PemEncoding.FindUtf8(fileContents);
Die wichtigste Neuerung ist die verbesserte Unterstützung für asynchrone Operationen. Die APIs zum Anzeigen von Formularen und Dialogen, die in .NET 9 noch experimentell waren und die Deaktivierung der Compiler-Warnung WFO5002 erforderten, sind jetzt vollständig stabil und ohne zusätzliche Konfiguration einsatzbereit. Die Methoden Form.ShowAsync, Form.ShowDialogAsync und TaskDialog.ShowDialogAsync ermöglichen die Erstellung einer wirklich reaktionsfähigen Oberfläche ohne Blockierungen, insbesondere bei der Arbeit mit mehreren Fenstern.
In .NET 10 wurden die fehlenden Editor-Typen aus dem .NET Framework, die mit UITypeEditor zusammenhängen, in die Plattform überführt. Sie stehen nun bei der Arbeit mit PropertyGrid und dem Aktionsbereich des Designers zur Verfügung. Ebenfalls behoben wurde die Funktionalität der SnapLines für benutzerdefinierte Designer.
Als Reaktion auf moderne Sicherheitsanforderungen wurde eine API zur Verhinderung unerwünschter Bildschirmaufzeichnungen hinzugefügt. Die Eigenschaft Form.ScreenCaptureMode ermöglicht eine flexible Steuerung der Sichtbarkeit eines Formulars bei der Aufnahme: den Inhalt ausblenden, das Fenster vollständig unkenntlich machen oder alles unverändert lassen. Dies ist besonders relevant für Anwendungen, die mit vertraulichen Daten arbeiten.
Die entscheidende Leistungsverbesserung betrifft die Steuerelemente CollectionView und CarouselView unter iOS und Mac Catalyst. Die optimierten Handler, die in .NET 9 noch als optionale Funktion verfügbar waren, sind jetzt standardmäßig aktiviert. Dies gewährleistet eine höhere Geschwindigkeit und Stabilität bei der Anzeige komplexer Listen mit benutzerdefinierten Vorlagen und reduziert den Ressourcenverbrauch.
Verwendet jetzt standardmäßig den optimierten Handler.
Die Komponente HybridWebView erhielt mehrere bedeutende Verbesserungen für eine engere Integration von Webcode und .NET:
Ereignisse des Lebenszyklus. Die Ereignisse WebViewInitializing und WebViewInitialized wurden hinzugefügt. Sie ermöglichen die Konfiguration der Web-Ansicht auf Plattformebene vor und nach ihrer Erstellung.
Eine bedeutende Neuerung ist die Möglichkeit, Anfragen innerhalb von BlazorWebView und HybridWebView abzufangen. Entwickler können Header ändern, Datenverkehr umleiten oder Antworten ersetzen, was vielfältige Möglichkeiten für Caching, Sicherheit und lokale Datenverarbeitung eröffnet.
{ if (e.Uri.ToString().Contains("api/secure")) { e.Handled = true; e.SetResponse(200, "OK", "application/json", GetCustomStream()); } };
In Blazor-Anwendungen ist das Streaming von Antworten für HttpClient jetzt standardmäßig aktiviert. Das bedeutet, dass die Methode response.Content.ReadAsStreamAsync() einen BrowserHttpReadStream anstelle eines MemoryStream zurückgibt, was den Speicherverbrauch reduziert, aber bei der Verwendung synchroner Operationen Aufmerksamkeit erfordert.
Zur Beibehaltung des bisherigen Verhaltens stehen Optionen zur Deaktivierung bereit:
<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>
HttpRequestMessage.SetBrowserResponseStreamingEnabled(false)
In .NET 10 wurde das Laden von Framework-Ressourcen für beide Modelle von Blazor-Anwendungen verbessert:
OverrideHtmlAssetPlaceholders auf true zu setzen und im <head> ein <link rel="preload" id="webassembly" />-Element hinzuzufügen.
Entwickler können nun nicht nur Funktionen aufrufen, sondern auch umfassend mit Objekten und deren Eigenschaften arbeiten:
Diese Möglichkeiten sind sowohl im asynchronen (IJSRuntime) als auch im synchronen (IJSInProcessRuntime) Modus verfügbar und eröffnen neue Szenarien für eine enge Integration von .NET- und JavaScript-Code in hybriden und Blazor-Anwendungen.
// Beispiel: JS-Klasse instanziieren und verwenden var classRef = await JSRuntime.InvokeConstructorAsync("jsInterop.TestClass", "Blazor!"); var text = await classRef.GetValueAsync<string>("text"); var textLength = await classRef.InvokeAsync<int>("getTextLength");
.NET 10 ist ein Release ohne großen Überraschungseffekt, dafür aber mit gründlichem Feinschliff. Die Sprache ist ausdrucksstärker geworden, WinForms moderner, MAUI stabiler und Blazor der „nativen“ Arbeit mit dem Browser noch einen Schritt näher gekommen.
Ein Update lohnt sich auf jeden Fall, selbst wenn man nicht auf der Suche nach Neuheiten ist: Die Behebungen von Legacy-Code und die Speicheroptimierungen zahlen sich von selbst aus.