Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Начиная с C# 15, модификатор можно применить closed к классу для объявления закрытой иерархии. Прямой подтип можно наследить только из закрытого класса в своей декларируемой сборке. Так как набор прямых потомков исправлен, выражение, обрабатывающее каждый прямой потомок, switch исчерпает закрытый базовый тип и не нуждается в руке по умолчанию.
// 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
Ограничение одной сборки применяется только к прямым потомкам закрытого класса. Класс, производный от закрытого класса, не закрывается, если вы также не пометите его closed. Так как Failed в предыдущем примере является обычной записью, другая сборка может быть производным от нее:
// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed
Если вы хотите предотвратить производные от Failed него, объявите его как sealed или closed.
Справочные документы по языку C# описывают последнюю выпущенную версию языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.
Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.
Tip
Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей об истории версий языка C#.
Note
closed — это контекстное ключевое слово. Он имеет особое значение, только если он отображается как модификатор в объявлении класса. Вы можете продолжать использовать closed в качестве идентификатора в других контекстах. Если необходимо использовать closed в качестве идентификатора в позиции, где модификатор также будет допустимым, префикс его с @ помощью (например, @closed), чтобы сообщить компилятору рассматривать его как идентификатор, а не модификатор.
Правила объявления
Модификатор closed является модификатором класса:
- Класс
closedнеявноabstract. Нельзя сочетатьclosedсsealedмодификатором илиstaticявнымabstractмодификатором. - Необходимо объявить прямой подтип закрытого класса в той же сборке и модуле, что и закрытый базовый класс.
- Класс, производный от закрытого класса, не закрыт. Примените модификатор еще раз, если требуется, чтобы производный
closedкласс также был закрыт.
Если универсальный класс непосредственно является производным от closed класса, каждый параметр типа в производном классе должен использоваться в спецификации базового класса. Это правило не относится к closed модификатору: закрытый созданный тип является универсальным типом, аргументы типа которого полностью указаны (например), в отличие от Tree<int>, напримерTree<T>. Правило гарантирует, что каждый закрытый созданный тип базового класса имеет ровно один соответствующий закрытый построенный тип среди прямых потомков, поэтому компилятор может подумать о исчерпывающей причине.
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
Исчерпывающие выражения коммутатора
switch Когда выражение обрабатывает каждый прямой потомок закрытого класса, компилятор считает коммутатор исчерпывающим и не создает предупреждение о неисчерпаемой готовности:
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.
};
Если параметр управления выражением имеет значение NULL, null становится другим возможным значением, которое должен обрабатывать коммутатор. Переключение JobStatus? является исчерпывающим только в том случае, если он также охватывает 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.
};
Если опустить null руку, компилятор предупреждает, что шаблон null не обрабатывается. То же правило применяется, является ли закрытый тип классом или структурой, поднятой на тип, допускающий значение NULL.
Дополнительные сведения о том, как компилятор определяет исчерпывающую эффективность, включая взаимодействие закрытых иерархий с универсальными ограничениями и специальными возможностями, см. в разделе "Шаблоны закрытой иерархии".
Параметры типа, ограниченные закрытым типом
Спецификация функции закрытых иерархий обрабатывает параметр типа, ограниченный закрытым классом, таким же, как и закрытый класс для проверки исчерпывающести: switch выражение, определяющее значение которого имеет такой параметр типа, является исчерпывающим при обработке каждого прямого потомка закрытого ограничения независимо от того, отображается ли параметр типа в методе или в содержащем типе:
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 the compiler treats
// this switch as exhaustive because every direct descendant is handled.
};
Спецификация языка C#
Дополнительные сведения см. в спецификации функции закрытых иерархий .