Neuerungen in C# 15

C# 15 enthält die folgenden neuen Features. Probieren Sie diese Features aus, indem Sie die neueste Visual Studio 2026-Insider-Version oder das .NET 11 Preview SDK verwenden:

C# 15 ist die neueste C#-Vorschauversion. .NET 11-Vorschauversionen unterstützen C# 15. Weitere Informationen finden Sie unter C#-Sprachversionsverwaltung.

Sie können das neueste .NET 11 Preview SDK von der .NET-Downloadseite herunterladen. Sie können auch Visual Studio 2026-Insider herunterladen, das das .NET 11 Preview-SDK enthält.

Auf der Seite "Neuerungen in C#" werden neue Features hinzugefügt, wenn sie in öffentlichen Vorschauversionen verfügbar sind. Der Arbeitssatzabschnitt der Roslyn-Featurestatusseite verfolgt, wenn anstehende Features in die Hauptzweige zusammengeführt werden.

Alle fehlerhaften Änderungen, die in C# 15 eingeführt wurden, finden Sie in unserem Artikel über fehlerhafte Änderungen.

Hinweis

Wir interessieren uns für Ihr Feedback zu diesen Features. Wenn Sie bei einem dieser neuen Features auf Probleme stoßen, erstellen Sie ein neues Problem im Repository dotnet/roslyn.

Argumente für Collection Expressions

Sie können Argumente an den Konstruktor oder die Factory-Methode der zugrunde liegenden Sammlung übergeben, indem Sie ein with(...)-Element als erstes Element in einem Sammlungsausdruck verwenden. Mit diesem Feature können Sie Kapazitäts-, Vergleichs- oder andere Konstruktorparameter direkt in der Syntax des Sammlungsausdrucks angeben.

Das folgende Beispiel zeigt, wie Sie ein Kapazitätsargument an den List<T>-Konstruktor und einen Komparator an den HashSet<T>-Konstruktor übergeben.

string[] values = ["one", "two", "three"];

// Pass capacity argument to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];

// Pass comparer argument to HashSet<T> constructor
HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
// set contains only one element because all strings are equal with OrdinalIgnoreCase

Weitere Informationen zu Auflistungsausdrucksargumenten finden Sie im Sprachreferenzartikel zu Auflistungsausdrücken oder der Featurespezifikation. Informationen zur Verwendung von Auflistungsausdrucksargumenten in Sammlungsinitialisierern finden Sie unter Object and Collection Initializers.

Unionstypen

C# 15 führt Union-Typen ein, die einen Wert darstellen, der einen von mehreren Falltypen sein kann. Deklarieren Sie eine Vereinigung mit dem union Schlüsselwort:

public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);

public union Pet(Cat, Dog, Bird);

Unions stellen implizite Konvertierungen von jedem Falltyp bereit, und der Compiler stellt sicher, dass switch Ausdrücke für alle Falltypen erschöpfend sind:

Pet pet = new Dog("Rex");

string name = pet switch
{
    Dog d => d.Name,
    Cat c => c.Name,
    Bird b => b.Name,
};

Die Laufzeit enthält die Typen UnionAttribute und IUnion beginnend mit .NET 11 Preview 5. Einige Features aus der Vorschlagsspezifikation sind noch nicht implementiert. Diese Features werden in zukünftigen Vorschauen verfügbar sein.

Weitere Informationen finden Sie unter Union-Typen in der Sprachreferenz oder in der Funktionsspezifikation.

Geschlossene Hierarchien

Ab C# 15 können Sie den closed Modifizierer auf eine Klasse anwenden, um eine geschlossene Hierarchie zu deklarieren. Eine geschlossene Klasse, von der nur innerhalb der deklarierenden Assembly abgeleitet werden kann, legt die Menge der direkten Nachfolgerelemente zum Kompilierungszeitpunkt fest:

public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;

Da der Compiler alle direkten Untergeordneten kennt, ist ein switch Ausdruck, der die einzelnen behandelt, erschöpfend und benötigt keinen Standardarm:

string Describe(GateState state) => state switch
{
    Closed => "closed",
    Open(var percent) => $"{percent}% open",
    // No warning: every direct descendant of 'GateState' is handled.
};

Der closed Modifizierer ist ein kontextbezogenes Schlüsselwort. Eine closed Klasse ist implizit abstract und kann nicht mit sealedstatic, oder einem expliziten abstract Modifizierer kombiniert werden. Die Ableitung ist nicht transitiv: Ein nicht geschlossenes Nachfolgerelement einer geschlossenen Klasse kann weiterhin von anderen Assemblys abgeleitet werden. Um die Vollständigkeitsprüfung in der Hierarchie weiter nach unten auszudehnen, markieren Sie auch zwischengelagerte Nachfolgerelemente closed.

Hinweis

In C# 15 Vorschauversion 5 liefert die Laufzeit System.Runtime.CompilerServices.ClosedAttribute derzeit noch nicht aus. Bis zu diesem Zeitpunkt muss jedes Projekt, das den closed Modifizierer verwendet, das Attribut selbst deklarieren:

namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ClosedAttribute : Attribute { }

Weitere Informationen finden Sie unter den Mustern für geschlossene Modifizierer und geschlossene Hierarchien in der Sprachreferenz oder in der Featurespezifikation. Sie können die Beispiele in diesem Abschnitt, einschließlich der Problemumgehung ClosedAttribute, aus dem Projekt keywords snippets im Repository dotnet/docs GitHub kopieren.

Speichersicherheit

C# 15 beginnt mit einer Multirelease-Anstrengung, die Speichersicherheit in der Sprache neu zu definieren. Ziel ist es, den unsafe Kontext mit den Vorgängen zu verknüpfen, die tatsächlich auf nicht verwalteten Speicher zugreifen, anstatt auf das Vorhandensein von Zeigertypen zu verweisen. Die meisten Schwachstellen bei der Speichersicherheit gehen auf diese Zugriffsoperationen zurück, daher sorgt die Sprache dafür, dass sie für Reviewer und Auditoren deutlich erkennbar sind.

Im vollständigen Modell kennzeichnet unsafe ein Mitglied als requires-unsafe: Die Prüfpflicht geht auf den Aufrufer über, der das Mitglied in einem unsafe-Kontext verwenden muss. Eine Assembly entscheidet sich für diese Erzwingung, und der Compiler zeichnet die Auswahl mit dem System.Runtime.CompilerServices.MemorySafetyRulesAttribute Attribut auf. Das Modell fügt außerdem ein safe kontextbezogenes Schlüsselwort hinzu, das extern Member und Felder mit explizitem Layout als sicher kennzeichnet. Gemeinsam machen diese Regeln die Grenzen potenzieller Speicherunsicherheiten in einem Programm explizit.

Der erste Schritt umfasst die Zeigerentspannungen. Wenn Sie mit der preview Sprachversion kompilieren, erfordern die folgenden Vorgänge keinen unsafe Kontext mehr:

  • Deklarieren eines Zeigertyps und Ermitteln der Adresse einer Variablen mit dem Operator &.
  • Die fixed Anweisung, die eine Variable anheftet.
  • Konvertieren eines stackalloc Ausdrucks in einen Zeiger.
  • Der auf einen beliebigen unverwalteten Typ angewendete sizeof-Operator.

Im folgenden Beispiel wird ein Zeiger ohne unsafe Kontext erstellt und angeheftet:

int number = 42;
int* pointer = &number;

int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
    // Dereferencing the pointer still requires an unsafe context.
}

Die Vorgänge, die auf den verweisenden Speicher zugreifen, z. B. Zeigerdereferenzierung (*p), Zeigermemmzugriff (), Zeigerelementzugriff (p->memberp[i]) und Funktionszeigeraufruf erfordern weiterhin einen unsafe Kontext.

Das requires-unsafe-Membermodell, die explizite Aktivierung der aktualisierten Speichersicherheitsregeln auf Assemblyebene und das safe kontextbezogene Schlüsselwort werden in einer späteren Vorschau eingeführt.

Weitere Informationen finden Sie unter "Unsicherer Code", "Zeigertypen" und "Funktionszeiger" in der Sprachreferenz oder in der Featurespezifikation.

Siehe auch