Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
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:
- Sammlungs-Ausdrucksargumente
- Union-Typen
- Geschlossene Hierarchien
- Indexer für Erweiterungen
-
Beschriftet
breakundcontinue - Speichersicherheit
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.
Indexer für Erweiterungen
Ab C# 15 können Sie Indexer in einem extension Block deklarieren. Mit Erweiterungsindexern können Sie einen Empfänger indizieren, als ob der Indexer für den Empfängertyp deklariert wurde. Da Indexer immer Instanzmember sind, muss ein Erweiterungsblock, der einen Indexer deklariert, einen benannten Empfängerparameter bereitstellen.
Im folgenden Beispiel wird für IEnumerable<int> ein Indexer mit ausschließlichem get-Zugriff deklariert, der das Element an der angegebenen Position zurückgibt:
public static class SequenceIndexer
{
extension(IEnumerable<int> sequence)
{
public int this[int index] => sequence.ElementAt(index);
}
}
Sie greifen über den Index auf den Empfänger zu, als wäre der Indexer ein Mitglied des Empfängertyps:
IEnumerable<int> numbers = Enumerable.Range(1, 10);
int third = numbers[2];
Weitere Informationen finden Sie in der Erweiterungsdeklaration in der Sprachreferenz oder in der Featurespezifikation.
Beschriftet break und continue
Ab C# 15 breakcontinue können Anweisungen eine Bezeichnung für ein eingeschlossenes Konstrukt benennen. Verwenden Sie ein beschriftetes break, um eine umschließende Schleife oder eine switch-Anweisung zu beenden. Verwenden Sie ein mit einer Beschriftung versehenes continue, um die nächste Iteration einer umschließenden Schleife zu starten.
Mit break und continue versehene Anweisungen ersetzen die Hilfskonstrukte, die Sie sonst verwenden würden, um den Kontrollfluss durch verschachtelte Schleifen zu lenken, etwa ein boolesches Flag, das Sie in einer inneren Schleife setzen und dann auf jeder äußeren Ebene prüfen, oder ein goto, das hinter die Schleifen springt. Die Zielschleife direkt in der Sprunganweisung zu benennen, erspart diesen Verwaltungsaufwand und macht den beabsichtigten Kontrollfluss leichter nachvollziehbar.
outer: for (int row = 0; row < grid.Height; row++)
{
for (int column = 0; column < grid.Width; column++)
{
if (grid[row, column].IsBlocked)
{
continue outer;
}
if (grid[row, column].IsGoal)
{
break outer;
}
}
}
Das Label steht direkt an der Schleife oder der switch-Anweisung, die es kennzeichnet. Ohne Label behalten break und continue ihr ursprüngliches Verhalten bei und zielen auf die innerste zutreffende Anweisung ab.
Die IDE0410-Formatierungsregel kennzeichnet boolesche Flags und Muster mit goto, die durch eine Sprunganweisung mit Bezeichnung ersetzt werden können, und zeigt jeweils Vorher-/Nachher-Beispiele dafür an.
Weitere Informationen finden Sie unter Jump-Anweisungen in der Sprachreferenz oder in der Featurespezifikation.
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üfverpflichtung 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
fixedAnweisung, die eine Variable anheftet. - Konvertieren eines
stackallocAusdrucks 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), Zeigermemberzugriff (p->member), Zeigerelementzugriff (p[i]) und Funktionszeigeraufruf erfordern weiterhin einen unsafe-Kontext.
Das requires-unsafe-Mitgliedsmodell, die explizite Aktivierung der aktualisierten Speichersicherheitsregeln auf Assemblyebene und das kontextbezogene safe Schlüsselwort werden in einer späteren Vorschauversion eingeführt.
Weitere Informationen finden Sie unter "Unsicherer Code", "Zeigertypen" und "Funktionszeiger" in der Sprachreferenz oder in der Featurespezifikation.