geschlossen (C#-Referenz)

Ab C# 15 können Sie den closed Modifizierer auf eine Klasse anwenden, um eine geschlossene Hierarchie zu deklarieren. Sie können nur einen direkten Untertyp von einer geschlossenen Klasse innerhalb der deklarierenden Assembly ableiten. Da der Satz von direkten Nachfolgern behoben ist, wird durch einen switch Ausdruck, der die einzelnen direkten untergeordneten Elemente behandelt, der den geschlossenen Basistyp ausschließt und keinen Standardarm benötigt.

// Assembly 1
public closed record class JobStatus;
public record class Queued : JobStatus;
public record class Running(int PercentComplete) : JobStatus;
public record class Completed(TimeSpan Elapsed) : JobStatus;
public record class Failed(string Error) : JobStatus;

// Assembly 2
public record class Paused : JobStatus; // Error: 'JobStatus' is a closed class

Die Gleiche Assemblyeinschränkung gilt nur für direkte Nachfolger der geschlossenen Klasse. Eine Klasse, die von einer geschlossenen Klasse abgeleitet wird, wird nicht selbst geschlossen, es sei denn, Sie markieren sie closedauch. Da Failed es sich im vorherigen Beispiel um einen einfachen Datensatz handelt, kann eine andere Assembly daraus abgeleitet werden:

// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed

Wenn Sie auch die Ableitung Failed verhindern möchten, deklarieren Sie sie als sealed oder closed.

Die C#-Sprachreferenz dokumentiert die zuletzt veröffentlichte Version der C#-Sprache. Außerdem enthält sie eine erste Dokumentation zu Funktionen in der öffentlichen Vorschau für die kommende Sprachversion.

In der Dokumentation werden alle Features identifiziert, die in den letzten drei Versionen der Sprache oder in der aktuellen öffentlichen Vorschau eingeführt wurden.

Tip

Informationen dazu, wann ein Feature erstmals in C# eingeführt wurde, finden Sie im Artikel zum Versionsverlauf der C#-Sprache.

Note

closed ist ein kontextbezogenes Schlüsselwort. Sie hat nur dann eine besondere Bedeutung, wenn sie als Modifizierer für eine Klassendeklaration angezeigt wird. Sie können weiterhin als Bezeichner in anderen Kontexten verwendet werden closed . Wenn Sie als Bezeichner an einer Position verwenden closed müssen, an der der Modifizierer ebenfalls gültig wäre, präfixieren @ Sie ihn mit dem Präfix (z. B @closed. ), um den Compiler anzuweisen, ihn anstelle des Modifizierers als Bezeichner zu behandeln.

Deklarationsregeln

Der closed Modifizierer ist ein Klassenmodifizierer:

  • Eine closed Klasse ist implizit abstract. Sie können nicht mit sealed, staticoder einem expliziten abstract Modifizierer kombinierenclosed.
  • Sie müssen einen direkten Untertyp einer geschlossenen Klasse in derselben Assembly und demselben Modul wie die geschlossene Basisklasse deklarieren.
  • Eine Klasse, die von einer geschlossenen Klasse abgeleitet wird, wird nicht selbst geschlossen. Wenden Sie den closed Modifizierer erneut an, wenn auch eine abgeleitete Klasse geschlossen werden soll.

Wenn eine generische Klasse direkt von einer closed Klasse abgeleitet wird, muss jeder Typparameter der abgeleiteten Klasse in der Basisklassenspezifikation verwendet werden. Diese Regel bezieht sich nicht auf den closed Modifizierer selbst: Ein geschlossener konstruierter Typ ist ein generischer Typ, dessen Typargumente vollständig angegeben sind (z Tree<int>. B. ), im Gegensatz zu einem offenen Typ wie Tree<T>. Die Regel stellt sicher, dass jeder geschlossene konstruierte Typ der Basisklasse genau einen entsprechenden geschlossenen, konstruierten Typ unter seinen direkten Nachfolgern aufweist, sodass der Compiler die Erschöpfenheit begründen kann.

public closed record class Tree<T>;

public record class Leaf<T>(T Value) : Tree<T>;                       // OK: 'T' appears in the base class
public record class Branch<T>(Tree<T> Left, Tree<T> Right) : Tree<T>; // OK: 'T' appears in the base class
public record class Constant<U>(U Value) : Tree<int> { } // Error: 'U' isn't used in the base class

Erschöpfende Switchausdrücke

Wenn ein switch Ausdruck alle direkten untergeordneten Elemente einer geschlossenen Klasse behandelt, betrachtet der Compiler den Switch als erschöpfend und generiert keine Warnung für nicht erschöpfende Werte:

public static string Describe(JobStatus status) => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled.
};

Wenn der Switch für den Ausdruck nullwertebar ist, wird ein weiterer möglicher Wert, null den der Switch verarbeiten muss. Eine Umstellung JobStatus? ist nur erschöpfend, wenn sie auch folgendes abdeckt null:

public static string DescribeOrUnknown(JobStatus? status) => status switch
{
    null => "unknown",
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: every direct descendant of 'JobStatus' is handled, and null is handled.
};

Wenn Sie den null Arm weglassen, warnt der Compiler, dass das Muster null nicht behandelt wird. Die gleiche Regel gilt, ob der geschlossene Typ eine Klasse oder eine Struktur ist, die auf einen nullfähigen Typ aufgehoben wird.

Weitere Informationen dazu, wie der Compiler erschöpfend bestimmt, einschließlich der Interaktion geschlossener Hierarchien mit generischen Einschränkungen und Barrierefreiheit, finden Sie unter "Geschlossene Hierarchiemuster".

Typparameter, die auf einen geschlossenen Typ beschränkt sind

Ein Typparameter, der auf eine geschlossene Klasse beschränkt ist, wird als geschlossene Klasse für Erschöpfende Prüfungen behandelt. Ein switch Ausdruck, dessen Regelwert einen solchen Typparameter aufweist, ist erschöpfend, wenn er alle direkten untergeordneten Elemente der geschlossenen Einschränkung behandelt:

public static string DescribeJob<X>(X status) where X : JobStatus => status switch
{
    Queued => "waiting to start",
    Running(var percent) => $"{percent}% complete",
    Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
    Failed(var error) => $"failed: {error}",
    // No warning: 'X' is constrained to a closed type, so its direct descendants exhaust the switch.
};

Diese Regel gilt, ob der Typparameter für eine Methode oder für den enthaltenden Typ angezeigt wird.

C#-Sprachspezifikation

Weitere Informationen finden Sie in der Featurespezifikation für geschlossene Hierarchien .

Siehe auch